美文网首页
go 的错误处理 error

go 的错误处理 error

作者: wayyyy | 来源:发表于2021-12-12 03:26 被阅读0次
    error 接口
    type error interface {
        Error() string
    }
    

    error 是一种内建的接口类型,不需要引用 任何包就可以直接使用。error 接口只声明了一个Error方法,任何实现了该方法的结构体都可以作为 error 来使用。
    标准库errors 包中的 errorString 就是实现了 error 接口的一个例子:

    type errorString struct {
        a string
    }
    
    func (e *errorString) Error() string {
        return e.s
    }
    
    异常处理

    针对 error 而言,异常处理包括如何检查错误,如何传递错误。

    • 检查error
      最常见的错误是和nil值比较,

    • 传递error
      在一个函数中收到一个error,往往需要附加一些上下文信息再把 error 继续向上层抛。
      最常见的添加附加上下文信息的方法是使用fmt.Errorf()

      if err != nil { 
          return fmt.Errorf("decompress %v: %v", name, err)
      }
      

      这种方式抛 error 有一个糟糕的问题,那就是原 error 信息和附加的信息被糅合在一起了。

    为了解决这一问题,Go 1.13 中引入了对error的优化,最核心的内容就是引入了 wrapError 这一新的 error 类型。

    • wrapError

      type wrapError struct {
          msg string
          err error
      }
      
      func (e *wrapError ) Error() string {
          return e.msg
      }
      
      func (e *wrapError ) Unwarp() error {
          return e.err
      }
      

      这样多个error 在函数之间传递,error 就被组织成了一个链式结构:

      image.png
    • fmt.Errorf()
      在go 1.13 中,fmt.Errorf() 新增了格式动词%w用于生成wrapError实例。

      func main() {
          err := errors.New("this is first error")
          warpErr1 := fmt.Errorf("this is second error: %w", err)
          warpErr2 := fmt.Errorf("this is thrid error: %w", warpErr1)
          fmt.Println(warpErr2)
      }
      // 输出:
      this is thrid error: this is second error: this is first error
      

      使用fmt.Errorf 有2点需要注意:

      • 每次只接受一个 %w
      • %w 只能用于匹配 error 参数
    • errors.Unwrap
      Unwrap 则是解开 wrap,返回成员error

      unWarpErr2 := errors.Unwrap(warpErr2)
      fmt.Println(unWarpErr2)
      // 输出:
      this is second error: this is first error
      

      其实现源码实现如下:

      func Unwrap(err error) error {
          // 检查是否实现了 Unwrap 函数
          // 如果没有实现 Unwrap 函数,则不支持 Unwrap
          u, ok := err.(interface { Unwrap() error })
          if !ok {
              return nil
          }
          return u.Unwrap()
      } 
      
    • errors.ls
      errors.ls() 用于检查特定的 error 链中是否包含了指定的 error 值。比如:

      
      

      其源码实现可能会是:

      func Is(err, target error) bool {
          for {
              if 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.As
      erross.As 用于从一个 error链中查找是否有指定的类型出现,如有,则把 error转换成该类型

    相关文章

      网友评论

          本文标题:go 的错误处理 error

          本文链接:https://www.haomeiwen.com/subject/yfzlfrtx.html