许多开发人员建议在 Go 中使用 fmt.Errorf 和 %w 动词来包装错误,但是这个方法不提供真正的递归包装。要使用 Is() 和 As() 递归检查错误,可以使用自定义错误类型。
这里有一个自定义错误类型 errorChain,支持错误包装和递归检查:
type errorChain struct { err error next *errorChain } func Wrap(errs ...error) error { out := errorChain{err: errs[0]} n := &out for _, err := range errs[1:] { n.next = &errorChain{err: err} n = n.next } return out }
启用递归检查的关键是在自定义类型上实现 Is() 和 As() 方法。这些方法允许对链中包含的错误进行错误比较,而不是链本身:
func (c errorChain) Is(err error) bool { return errors.Is(c.err, err) } func (c errorChain) As(target any) bool { return errors.As(c.err, target) }
使用这些方法,您可以包装错误并执行递归检查:
errs := Wrap(errors.New("error 0"), errors.New("error 1"), errors.New("error 2")) fmt.Println(errors.Is(errs, errors.New("error 0"))) // true fmt.Println(errors.Is(errs, errors.New("error 1"))) // true fmt.Println(errors.Is(errs, errors.New("error 2"))) // true
errorChain 中的 Unwrap() 方法允许您遍历链中包装的错误:
var currentError error = errs for { currentError = errors.Unwrap(currentError) if currentError == nil { break } fmt.Println(currentError) }
此示例打印链中的所有错误:
error 0 error 1 error 2
以上是如何在 Go 中实现真正的递归错误包装和展开?的详细内容。更多信息请关注PHP中文网其他相关文章!