Go 最新版本 1.13 中新增了 errors 的一些特性,有助于咱们更优雅的处理业务逻辑中报错的问题。
本文主要展现errors
包中新增方法的用法。
核心思想:套娃
啥意思呢?这玩意就像套娃同样,从上往下扒,拿走一个还有一个,再拿走一个,诶还有一个,若是你愿意,能够一直扒到最底下没有了为止。shell
使用 %w
参数返回一个被包装的 errorcode
err1 := errors.New("new error") err2 := fmt.Errorf("err2: [%w]", err1) err3 := fmt.Errorf("err3: [%w]", err2) fmt.Println(err3)
// output err3: [err2: [new error]]
err2
就是一个合法的被包装的 error,一样地,err3
也是一个被包装的 error,如此能够一直套下去。递归
type WarpError struct { msg string err error } func (e *WarpError) Error() string { return e.msg } func (e *WrapError) Unwrap() error { return e.err }
以前看过源码的同窗可能已经知道了,这就是 fmt/errors.go
中关于 warp 的结构。
就,很简单。自定义一个实现了 Unwrap
方法的 struct 就能够了。get
err1 := errors.New("new error") err2 := fmt.Errorf("err2: [%w]", err1) err3 := fmt.Errorf("err3: [%w]", err2) fmt.Println(errors.Unwrap(err3)) fmt.Println(errors.Unwrap(errors.Unwrap(err3)))
// output err2: [new error] new error
当多层调用返回的错误被一次次地包装起来,咱们在调用链上游拿到的错误如何判断是不是底层的某个错误呢?它递归调用 Unwrap 并判断每一层的 err 是否相等,若是有任何一层 err 和传入的目标错误相等,则返回 true。
源码
err1 := errors.New("new error") err2 := fmt.Errorf("err2: [%w]", err1) err3 := fmt.Errorf("err3: [%w]", err2) fmt.Println(errors.Is(err3, err2)) fmt.Println(errors.Is(err3, err1))
// output true true
这个和上面的 errors.Is
大致上是同样的,区别在于 Is
是严格判断相等,即两个 error
是否相等。
而 As
则是判断类型是否相同,并提取第一个符合目标类型的错误,用来统一处理某一类错误。string
type ErrorString struct { s string } func (e *ErrorString) Error() string { return e.s } var targetErr *ErrorString err := fmt.Errorf("new error:[%w]", &ErrorString{s:"target err"}) fmt.Println(errors.As(err, &targetErr))
// output true
Is
As
两个方法已经预留了口子,能够由自定义的 error struct 实现并覆盖调用。