在 Go 1.23 中,errors.Is 增加了 nil 检查,这使得在处理错误时更简洁明了。这是 Go 1.23rc 的 release notes[1]
不过里面并没有对 errors.Is 的修改做太多说明。在 Go 1.23 之前,errors.Is 不会检查正在检查的错误是否为零。当时的代码[2]如下:
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflectlite.TypeOf(target).Comparable()
return is(err, target, isComparable)
}
因此,要检查函数返回的错误是否是特定错误,就必须使用嵌套的 if 语句,就像这样:
err := foo()
if err != nil {
if errors.Is(err, errorBar) {
// handle error Bar
}
if errors.Is(err, errorBar2) {
// handle error Bar2
}
// handle other errors
}
虽然这些代码可能不会引起任何问题,但并不优雅。
在 Go 1.23 中,现在只需单层深度即可处理错误检查,无需嵌套 if 语句。这一改进归功于以下代码变更:
func Is(err, target error) bool {
if err == nil || target == nil {
return err == target
}
isComparable := reflectlite.TypeOf(target).Comparable()
return is(err, target, isComparable)
}
以前,errors.Is 只检查目标错误(即预定义错误)是否为零。但现在它也会检查实际返回的错误是否为零。因此,我们可以对代码进行如下改进:
err := foo()
if errors.Is(err, errorBar) {
// handle error Bar
}
if errors.Is(err, errorBar2) {
// handle error Bar2
}
if err != nil {
// handle other errors
}
笔者认为这种方法比以前的代码更好。虽然看起来只是一个小改动,但与旧版本相比,它大大提高了可读性,降低了复杂性,避免了不必要的 nil panic。
前面的代码包含嵌套的 if 语句,尽管最初编写时看起来简单明了,但日后阅读时可能会更加混乱和复杂。
go1.23 release notes: https://tip.golang.org/doc/go1.23
[2]wrap.go: https://github.com/golang/go/blob/go1.22.5/src/errors/wrap.go#L44-L51