go的errors
用
fmt.Errorf
创建嵌套errorfmt.Errorf
如果含%w
,则会创建wrapError
// go1.18/src/fmt/errors.go
func Errorf(format string, a ...any) error {
p := newPrinter()
// wrapErrs is set when the format string may contain a %w verb.
p.wrapErrs = true
p.doPrintf(format, a)
s := string(p.buf)
var err error
// 如果格式中没有%w,则创建一个新的err,否则创建wrapError
if p.wrappedErr == nil {
err = errors.New(s)
} else {
err = &wrapError{s, p.wrappedErr}
}
p.free()
return err
}
而
wrapError
有Error() string
方法,符合error接口;另外还有Unwrap() error
方法type wrapError struct {
msg string
err error
}
func (e *wrapError) Error() string {
return e.msg
}
func (e *wrapError) Unwrap() error {
return e.err
}
用
errors.Is
递归检查嵌套error是否某个错误循环
errors.Unwrap
解除嵌套,如果解出的值== target
或者Is(target)
,就返回true
直至解出的是
nil
,就返回false
// go1.18/src/errors/wrap.go
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflectlite.TypeOf(target).Comparable()
for {
if isComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
if err = Unwrap(err); err == nil {
return false
}
}
}
而
errors.Unwrap
就是检查有没Unwrap接口,有就Unwrap,否则返回nil
// go1.18/src/errors/wrap.go
func Unwrap(err error) error {
u, ok := err.(interface {
Unwrap() error
})
if !ok {
return nil
}
return u.Unwrap()
}
用
errors.As
抽取链中某类型的error,并赋值到另一个变量中一般用法:创建一个某类型的指针的空变量,将该指针传递给
errors.As
,则该指针能赋值为同类型error的报错信息var badInputErr *BadInputError
if errors.As(err, &badInputErr) {
fmt.Printf("bad input error occured: %s\n", badInputErr)
}
也是循环
Unwrap
,然后检查能否赋值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
}
参考