这个包以前有看过的,很简单,只是没注意原来还有个 wrap.go
errors.go
这个就很简单了,一个实现了 error
接口的 errorString
结构体,前面的注释是关于 Unwrap
的,那就放到下个文件写。这里直接删掉了前面五十多行的注释。
// src/errors/errors.go ---- line 54
package errors
// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
至于为啥没有 error
接口,我记得以前看的时候这个文件里确实是有的,现在为啥没有了。其实不是没有了,接口的定义在 buildin 里面哈哈哈。
// src/buildin/buildin.go ---- line 258
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}
wrap.go
这个也很简单,就三个函数,分别是 Unwrap
, Is
, As
// src/errors/wrap.go ---- line 11
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
u, ok := err.(interface {
Unwrap() error
})
if !ok {
return nil
}
return u.Unwrap()
}
判断参数 err
有没有实现那个匿名接口,也就是看它的类型有没有 Unwrap
方法,有就返回调用结果,没就返回 nil
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
//
// An error type might provide an Is method so it can be treated as equivalent
// to an existing error. For example, if MyError defines
//
// func (m MyError) Is(target error) bool { return target == os.ErrExist }
//
// then Is(MyError{}, os.ErrExist) returns true. See syscall.Errno.Is for
// an example in the standard library.
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
}
// TODO: consider supporting target.Is(err). This would allow
// user-definable predicates, but also may allow for coping with sloppy
// APIs, thereby making it easier to get away with them.
if err = Unwrap(err); err == nil {
return false
}
}
}
Is
函数就是判断两个 error
是否相同。下面的 for
循环很有趣,在循环前先通过反射判断参数 target
是不是一个可比较的类型,然后把参数 err
一层一层的 Unwrap
,每一层都去和 target
比较一下,不等就继续 Unwrap
,直到最里层不能再解封装了,根据 Unwrap
方法,返回 nil
,于是这个 Is
函数就返回 false
再看 As
函数,这个 As
不要理解成英语单词的 as 了,不然就很难理解,其实是单词 Assign 的,赋值,就是尝试把 err
赋值给 target
// src/errors/wrap.go ---- line 61
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true. Otherwise, it returns false.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// An error type might provide an As method so it can be treated as if it were a
// a different error type.
//
// As panics if target is not a non-nil pointer to either a type that implements
// error, or to any interface type.
func As(err error, target interface{}) 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")
}
if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for err != nil {
if reflectlite.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflectlite.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}
var errorType = reflectlite.TypeOf((*error)(nil)).Elem()
直接翻译一下注释的第一段吧。 As
函数在 err
的封装链中找到第一个匹配 target
的 error
,如果找到了,就把 target
设置为找到的那个 error
的值,并且返回 true
,否则(也就是没找到匹配的 error
)返回 false
涉及到一些反射的内容,还没看到,不过还是勉强能理解的。
顺便一说 Is
和 As
函数的 for
循环风格不统一啊,都是判 err != nil
,一个要放在 if
判,一个放在 for
的条件判,虽然没有影响,但我寻思着这两个函数不是同一个人写的?