这个包以前有看过的,很简单,只是没注意原来还有个 wrap.go

errors.go

这个就很简单了,一个实现了 error 接口的 errorString 结构体,前面的注释是关于 Unwrap 的,那就放到下个文件写。这里直接删掉了前面五十多行的注释。

  1. // src/errors/errors.go ---- line 54
  2. package errors
  3. // New returns an error that formats as the given text.
  4. // Each call to New returns a distinct error value even if the text is identical.
  5. func New(text string) error {
  6. return &errorString{text}
  7. }
  8. // errorString is a trivial implementation of error.
  9. type errorString struct {
  10. s string
  11. }
  12. func (e *errorString) Error() string {
  13. return e.s
  14. }

至于为啥没有 error 接口,我记得以前看的时候这个文件里确实是有的,现在为啥没有了。其实不是没有了,接口的定义在 buildin 里面哈哈哈。

  1. // src/buildin/buildin.go ---- line 258
  2. // The error built-in interface type is the conventional interface for
  3. // representing an error condition, with the nil value representing no error.
  4. type error interface {
  5. Error() string
  6. }

wrap.go

这个也很简单,就三个函数,分别是 Unwrap, Is, As

  1. // src/errors/wrap.go ---- line 11
  2. // Unwrap returns the result of calling the Unwrap method on err, if err's
  3. // type contains an Unwrap method returning error.
  4. // Otherwise, Unwrap returns nil.
  5. func Unwrap(err error) error {
  6. u, ok := err.(interface {
  7. Unwrap() error
  8. })
  9. if !ok {
  10. return nil
  11. }
  12. return u.Unwrap()
  13. }

判断参数 err 有没有实现那个匿名接口,也就是看它的类型有没有 Unwrap 方法,有就返回调用结果,没就返回 nil

  1. // Is reports whether any error in err's chain matches target.
  2. //
  3. // The chain consists of err itself followed by the sequence of errors obtained by
  4. // repeatedly calling Unwrap.
  5. //
  6. // An error is considered to match a target if it is equal to that target or if
  7. // it implements a method Is(error) bool such that Is(target) returns true.
  8. //
  9. // An error type might provide an Is method so it can be treated as equivalent
  10. // to an existing error. For example, if MyError defines
  11. //
  12. // func (m MyError) Is(target error) bool { return target == os.ErrExist }
  13. //
  14. // then Is(MyError{}, os.ErrExist) returns true. See syscall.Errno.Is for
  15. // an example in the standard library.
  16. func Is(err, target error) bool {
  17. if target == nil {
  18. return err == target
  19. }
  20. isComparable := reflectlite.TypeOf(target).Comparable()
  21. for {
  22. if isComparable && err == target {
  23. return true
  24. }
  25. if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
  26. return true
  27. }
  28. // TODO: consider supporting target.Is(err). This would allow
  29. // user-definable predicates, but also may allow for coping with sloppy
  30. // APIs, thereby making it easier to get away with them.
  31. if err = Unwrap(err); err == nil {
  32. return false
  33. }
  34. }
  35. }

Is 函数就是判断两个 error 是否相同。下面的 for 循环很有趣,在循环前先通过反射判断参数 target 是不是一个可比较的类型,然后把参数 err 一层一层的 Unwrap,每一层都去和 target 比较一下,不等就继续 Unwrap,直到最里层不能再解封装了,根据 Unwrap 方法,返回 nil ,于是这个 Is 函数就返回 false


再看 As 函数,这个 As 不要理解成英语单词的 as 了,不然就很难理解,其实是单词 Assign 的,赋值,就是尝试把 err 赋值给 target

  1. // src/errors/wrap.go ---- line 61
  2. // As finds the first error in err's chain that matches target, and if so, sets
  3. // target to that error value and returns true. Otherwise, it returns false.
  4. //
  5. // The chain consists of err itself followed by the sequence of errors obtained by
  6. // repeatedly calling Unwrap.
  7. //
  8. // An error matches target if the error's concrete value is assignable to the value
  9. // pointed to by target, or if the error has a method As(interface{}) bool such that
  10. // As(target) returns true. In the latter case, the As method is responsible for
  11. // setting target.
  12. //
  13. // An error type might provide an As method so it can be treated as if it were a
  14. // a different error type.
  15. //
  16. // As panics if target is not a non-nil pointer to either a type that implements
  17. // error, or to any interface type.
  18. func As(err error, target interface{}) bool {
  19. if target == nil {
  20. panic("errors: target cannot be nil")
  21. }
  22. val := reflectlite.ValueOf(target)
  23. typ := val.Type()
  24. if typ.Kind() != reflectlite.Ptr || val.IsNil() {
  25. panic("errors: target must be a non-nil pointer")
  26. }
  27. if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
  28. panic("errors: *target must be interface or implement error")
  29. }
  30. targetType := typ.Elem()
  31. for err != nil {
  32. if reflectlite.TypeOf(err).AssignableTo(targetType) {
  33. val.Elem().Set(reflectlite.ValueOf(err))
  34. return true
  35. }
  36. if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
  37. return true
  38. }
  39. err = Unwrap(err)
  40. }
  41. return false
  42. }
  43. var errorType = reflectlite.TypeOf((*error)(nil)).Elem()

直接翻译一下注释的第一段吧。 As 函数在 err 的封装链中找到第一个匹配 targeterror,如果找到了,就把 target 设置为找到的那个 error 的值,并且返回 true,否则(也就是没找到匹配的 error)返回 false


涉及到一些反射的内容,还没看到,不过还是勉强能理解的。


顺便一说 IsAs 函数的 for 循环风格不统一啊,都是判 err != nil,一个要放在 if 判,一个放在 for 的条件判,虽然没有影响,但我寻思着这两个函数不是同一个人写的?