如果这个 err 自己实现了 interface{ Is(error) bool }
接口,通过接口断言,可以调用 Is
方法判断 err 是否与 target 相等 。
否则递归调用 Unwrap
方法拆包装,返回下一层的 error 去判断是否与 target 相等 。
errors.As提取指定类型的错误,判断包装的 error 链中,某一个 error 的类型是否与 target 相同,并提取第一个符合目标类型的错误的值,将其赋值给 target 。
type TypicalErr struct { e string}?func (t TypicalErr) Error() string { return t.e}?func main() { err := TypicalErr{"typical error"} err1 := fmt.Errorf("wrap err: %w", err) err2 := fmt.Errorf("wrap err1: %w", err1) var e TypicalErr if !errors.As(err2, &e) { panic("TypicalErr is not on the chain of err2") } println("TypicalErr is on the chain of err2") println(err == e)}/*打印结果:TypicalErr is on the chain of err2true*/
来看一下 error.As
方法的源码:
func As(err error, target any) bool { if target == nil { panic("errors: target cannot be nil") } val := reflectlite.ValueOf(target) typ := val.Type() if typ.Kind() != reflectlite.Ptr || val.IsNil() { panic("errors: target must be a non-nil pointer") } targetType := typ.Elem() if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) { panic("errors: *target must be interface or implement error") } for err != nil { if reflectlite.TypeOf(err).AssignableTo(targetType) { val.Elem().Set(reflectlite.ValueOf(err)) return true } if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) { return true } err = Unwrap(err) } return false}
源码 for 循环前的部分是用来约束 target 参数的类型,要求其是一个非空的指针类型 。
此外要求 *target
是一个接口或者实现了 error 接口 。
for 循环判断 err 是否可以赋值给 target 所属类型,如果可以则赋值返回 true 。
如果 err 实现了自己的 As
方法,则调用其逻辑,否则也是走递归拆包的逻辑 。
小结后续将继续分享一些源码解读的文章,关于 Go 语言的学习,我也开源了一个 GitHub 仓库,正在更新中,你也可以从我往期的文章中看到一些说明 。
经验总结扩展阅读
- 华为手机如何截屏(华为手势截屏)
- 华为手机如何截屏(华为手机如何截长屏)
- 华为手机如何全部截屏(长截屏教程华为)
- 支付宝如何开通借呗额度(支付宝借呗额度没了还能恢复吗)
- 地暖管如何安装?
- 彩钢瓦该如何安装?
- 仿古隔断如何进行保养?
- 内墙腻子粉该如何进行施工?
- 如何防止老年斑?
- 如何预防黄褐斑产生?