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 仓库,正在更新中,你也可以从我往期的文章中看到一些说明 。
推荐阅读
- 微信怎么建群步骤(如何增加微信群人数)
- 微信如何建立家群(如何建立微信朋友圈)
- 微信怎么建群微信如何建群(怎样建新群并且设自己为群主)
- 华为手机如何截屏(华为手势截屏)
- 华为手机如何截屏(华为手机如何截长屏)
- 华为手机如何全部截屏(长截屏教程华为)
- 支付宝如何开通借呗额度(支付宝借呗额度没了还能恢复吗)
- 98年属虎女事业发展如何 赶紧来看看她们的情况
- 手相女右手解析 教你如何看懂女人的手相
- 家中有老鼠如何驱赶 家里有老鼠怎么办才能快速驱赶