errors.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // Package errors provides error handling utilities.
  2. package errors
  3. import (
  4. "reflect"
  5. )
  6. // WalkFunc is the signature of the Walk callback function. The function gets the
  7. // current error in the chain and should return true if the chain processing
  8. // should be aborted.
  9. type WalkFunc func(error) bool
  10. // Walk invokes the given function for each error in the chain. If the
  11. // provided functions returns true or no further cause can be found, the process
  12. // is stopped and no further calls will be made.
  13. //
  14. // The next error in the chain is determined by the following rules:
  15. //
  16. // the return value of this method is used.
  17. // - If the current error has a `Unwrap() error` method
  18. // the return value of this method is used.
  19. // - If the current error has a `Unwrap() []error` method
  20. // the return values of this method is used.
  21. // - Common errors in the Go runtime that contain an Err field will use this value.
  22. func Walk(err error, f WalkFunc) {
  23. for prev := err; err != nil; prev = err {
  24. if f(err) {
  25. return
  26. }
  27. switch e := err.(type) {
  28. case multiWrapper:
  29. for _, err = range e.Unwrap() {
  30. Walk(err, f)
  31. }
  32. return
  33. case causer:
  34. err = e.Cause()
  35. case wrapper:
  36. err = e.Unwrap()
  37. default:
  38. // Unpack any struct or *struct with a field of name Err which satisfies
  39. // the error interface. This includes *url.Error, *net.OpError,
  40. // *os.SyscallError and many others in the stdlib.
  41. errType := reflect.TypeOf(err)
  42. errValue := reflect.ValueOf(err)
  43. if errValue.IsValid() && errType.Kind() == reflect.Ptr {
  44. errType = errType.Elem()
  45. errValue = errValue.Elem()
  46. }
  47. if errValue.IsValid() && errType.Kind() == reflect.Struct {
  48. if errField := errValue.FieldByName("Err"); errField.IsValid() {
  49. errFieldValue := errField.Interface()
  50. if newErr, ok := errFieldValue.(error); ok {
  51. err = newErr
  52. }
  53. }
  54. }
  55. }
  56. if reflect.DeepEqual(err, prev) {
  57. break
  58. }
  59. }
  60. }
  61. type causer interface {
  62. Cause() error
  63. }
  64. type wrapper interface {
  65. Unwrap() error
  66. }
  67. type multiWrapper interface {
  68. Unwrap() []error
  69. }