github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/docs/005-errors包源码分析.md (about)

     1  ## errors 
     2  
     3  ```go
     4  // The error built-in interface type is the conventional interface for
     5  // representing an error condition, with the nil value representing no error.
     6  type error interface {
     7  	Error() string
     8  }
     9  ``` 
    10  
    11  任何实现这个error interface 的类型/结构体都都可以赋值给error 
    12  
    13  
    14  第三方库: github.com/pkg/errors
    15  
    16  ```go
    17  // Wrap annotates cause with a message.
    18  func Wrap(cause error, message string) error
    19  // Cause unwraps an annotated error.
    20  func Cause(err error) error
    21  ```
    22  通过 Wrap 可以将一个错误,加上一个字符串,“包装”成一个新的错误;通过 Cause 则可以进行相反的操作,将里层的错误还原。
    23  
    24  ```go
    25  func ReadFile(path string) ([]byte, error) {
    26  	f, err := os.Open(path)
    27  	if err != nil {
    28  		return nil, errors.Wrap(err, "open failed")
    29  	}
    30  	defer f.Close()
    31  	
    32  	buf, err := ioutil.ReadAll(f)
    33  	if err != nil {
    34  		return nil, errors.Wrap(err, "read failed")
    35  	}
    36  	return buf, nil
    37  }
    38  ```
    39  
    40  示例 一个错误可能被处理多次 
    41  
    42  ```go
    43  func Write(w io.Writer, buf []byte) error { 
    44  	_, err := w.Write(buf)
    45  	if err != nil {
    46  		// annotated error goes to log file
    47  		log.Println("unable to write:", err)
    48  	
    49  		// unannotated error returned to caller return err
    50  		return err
    51  	}
    52  	return nil
    53  }
    54  ```
    55  优化方案
    56  
    57  ```go
    58  func Write(w io.Write, buf []byte) error {
    59  	_, err := w.Write(buf)
    60  	return errors.Wrap(err, "write failed")
    61  }
    62  ```
    63  
    64  在golang 1.13 开始,为了支持 wrapping,fmt.Errorf 增加了 %w 的格式,并且在 error 包增加了三个函数:errors.Unwrap,errors.Is,errors.As。
    65  
    66  fmt.Errorf
    67  
    68  使用 fmt.Errorf 加上 %w 格式符来生成一个嵌套的 error,它并没有像 pkg/errors 那样使用一个 Wrap 函数来嵌套 error,非常简洁。
    69  
    70  Unwrap
    71  
    72  func Unwrap(err error) error
    73  
    74  将嵌套的 error 解析出来,多层嵌套需要调用 Unwrap 函数多次,才能获取最里层的 error。
    75  
    76  ```go
    77  func Unwrap(err error) error {
    78      // 判断是否实现了 Unwrap 方法
    79  	u, ok := err.(interface {
    80  		Unwrap() error
    81  	})
    82  	// 如果不是,返回 nil
    83  	if !ok {
    84  		return nil
    85  	}
    86  	// 调用 Unwrap 方法返回被嵌套的 error
    87  	return u.Unwrap()
    88  }
    89  ```
    90  对 err 进行断言,看它是否实现了 Unwrap 方法,如果是,调用它的 Unwrap 方法。否则,返回 nil。
    91  
    92  Is
    93  
    94  func Is(err, target error) bool
    95  
    96  判断 err 是否和 target 是同一类型,或者 err 嵌套的 error 有没有和 target 是同一类型的,如果是,则返回 true。
    97  
    98  ```go
    99  func Is(err, target error) bool {
   100  	if target == nil {
   101  		return err == target
   102  	}
   103  
   104  	isComparable := reflectlite.TypeOf(target).Comparable()
   105  	
   106  	// 无限循环,比较 err 以及嵌套的 error
   107  	for {
   108  		if isComparable && err == target {
   109  			return true
   110  		}
   111  		// 调用 error 的 Is 方法,这里可以自定义实现
   112  		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
   113  			return true
   114  		}
   115  		// 返回被嵌套的下一层的 error
   116  		if err = Unwrap(err); err == nil {
   117  			return false
   118  		}
   119  	}
   120  }
   121  ```
   122  
   123  通过一个无限循环,使用 Unwrap 不断地将 err 里层嵌套的 error 解开,再看被解开的 error 是否实现了 Is 方法,并且调用它的 Is 方法,当两者都返回 true 的时候,整个函数返回 true。
   124  
   125  As
   126  
   127  func As(err error, target interface{}) bool
   128  
   129  从 err 错误链里找到和 target 相等的并且设置 target 所指向的变量。
   130  
   131  ```go
   132  func As(err error, target interface{}) bool {
   133      // target 不能为 nil
   134  	if target == nil {
   135  		panic("errors: target cannot be nil")
   136  	}
   137  	
   138  	val := reflectlite.ValueOf(target)
   139  	typ := val.Type()
   140  	
   141  	// target 必须是一个非空指针
   142  	if typ.Kind() != reflectlite.Ptr || val.IsNil() {
   143  		panic("errors: target must be a non-nil pointer")
   144  	}
   145  	
   146  	// 保证 target 是一个接口类型或者实现了 Error 接口
   147  	if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
   148  		panic("errors: *target must be interface or implement error")
   149  	}
   150  	targetType := typ.Elem()
   151  	for err != nil {
   152  	    // 使用反射判断是否可被赋值,如果可以就赋值并且返回true
   153  		if reflectlite.TypeOf(err).AssignableTo(targetType) {
   154  			val.Elem().Set(reflectlite.ValueOf(err))
   155  			return true
   156  		}
   157  		
   158  		// 调用 error 自定义的 As 方法,实现自己的类型断言代码
   159  		if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
   160  			return true
   161  		}
   162  		// 不断地 Unwrap,一层层的获取嵌套的 error
   163  		err = Unwrap(err)
   164  	}
   165  	return false
   166  }
   167  ```
   168  
   169  返回 true 的条件是错误链里的 err 能被赋值到 target 所指向的变量;或者 err 实现的 As(interface{}) bool 方法返回 true。
   170  
   171  前者,会将 err 赋给 target 所指向的变量;后者,由 As 函数提供这个功能。
   172  
   173  如果 target 不是一个指向“实现了 error 接口的类型或者其它接口类型”的非空的指针的时候,函数会 panic。
   174