在Go中包装错误是指在返回的错误中添加额外的上下文信息,如发生错误的函数名称、原因、类型等。这种技术最常用于创建清晰的错误信息,当你想快速准确地定位问题的来源时,这对调试工作特别有用。
要在Go中包装一个错误,你需要使用
fmt.Errorf(format string, a ...interface{}) error
函数创建一个新的错误,
在format 中使用动词**%w** 。
var ErrorCritical = errors.New("critical error")
...
wrapped := fmt.Errorf("[functionName] internal error: %w", ErrorCritical)
由此产生的错误是一个链,其中包裹的错误可以使用 errors.Unwrap()函数 "解开"。
fmt.Println(errors.Unwrap(wrapped) == ErrorCritical) // true
也可以检查一个给定的错误是否存在于链中的任何地方,这要感谢 errors.Is()和 errors.As()函数。关于如何包装、解包和测试错误类型的细节,请看下面的例子。
查看更多在Go中使用and处理错误的例子
errors.Is()和errors.As()函数处理错误的更多例子,请看我们的其他教程。
例子
在第一个例子中,我们创建了getError() 函数,该函数根据参数设置返回一个非包覆、单包覆或双包覆错误。我们包住的错误是一个简单的内置error 实例。
| |
输出。
is error internal: [getData] level 1 error: internal error
unwrapped error: internal error
---
is error internal: [getData] level 2 error: [getData] level 1 error: internal error
unwrapped error: [getData] level 1 error: internal error
unwrapped unwrapped error: internal error
让我们看一下main() 函数和输出。在第25-29 行,我们得到一个单一的包裹错误,并测试它是否是一个ErrorInternal 错误。正如你所看到的,该 errors.Is()函数返回true ,因为它检查链中的任何错误是否与目标匹配。错误是否被包起来并不重要。在这种情况下,一个简单的比较if err == ErrorInternal ,会得到false ,所以一般来说,使用 errors.Is()函数来比较错误是否相等。然后,我们用 errors.Unwrap()并将其打印到标准输出。解除对错误的包装后,就会得到我们之前包装的ErrorInternal 。
在第33-39 行中,我们得到一个双重包装的错误。该 errors.Is()返回ErrorInternal 在链中,尽管它是双包的。正如你所期望的那样,需要进行双重解包才能得到ErrorInternal 。
同样的,你也可以对特定类型的错误进行包装、解包和测试。请看下面的第二个例子。其结果与第一个例子类似,都是一个简单的error 实例。唯一的区别是使用了 errors.As()函数而不是 errors.Is()来检查链中的错误是否属于特定类型。
更多错误处理的例子,使用
errors.Is()和errors.As()可以在这里找到。
| |
输出。
is error internal: level 1 error: [getData] error internal
unwrapped error: [getData] error internal
---
is error internal: level 2 error: level 1 error: [getData] error internal
unwrapped error: level 1 error: [getData] error internal
unwrapped unwrapped error: [getData] error internal