设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 重新 试卷 创业者
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

一文悟透备受争议的 Go 语言错误处理(5)

发布时间:2019-09-19 12:45 所属栏目:21 来源:佚名
导读:使用第三方的 error 包就可以比较完美的解决问题: funcWrite(wio.Write,buf[]byte)error{ _,err:=w.Write(buf) returnerrors.Wrap(err,writefailed) } 返回的错误,对于人和机器而言,都是友好的。 小结 这一部分

使用第三方的 error 包就可以比较完美的解决问题:

  1. func Write(w io.Write, buf []byte) error { 
  2.     _, err := w.Write(buf) 
  3.     return errors.Wrap(err, "write failed") 

返回的错误,对于人和机器而言,都是友好的。

小结

这一部分主要讲了处理 error 的一些原则,引入了第三方的 errors 包,使得错误处理变得更加优雅。

作者最后给出了一些结论:

  • errors 就像对外提供的 API 一样,需要认真对待。
  • 将 errors 看成黑盒,判断它的行为,而不是类型。
  • 尽量不要使用 sentinel errors。
  • 使用第三方的错误包来包裹 error(errors.Wrap),使得它更好用。
  • 使用 errors.Cause 来获取底层的错误。

胎死腹中的 try 提案

之前已经出现用 “check & handle” 关键字和 “try 内置函数”改进错误处理流程的提案,目前 try 内置函数的提案已经被官方提前拒绝,原因是社区里一边倒地反对声音。

关于这两个提案的具体内容见参考资料【check & handle】和【try 提案】。

go 1.13 的改进

有一些 Go 语言失败的尝试,比如 Go 1.5 引入的 vendor 和 internal 来管理包,最后被滥用而引发了很多问题。因此 Go 1.13 直接抛弃了 GOPATH 和 vendor 特性,改用 module 来管理包。

柴大在《Go 语言十年而立,Go2 蓄势待发》一文中表示:

比如最近 Go 语言之父之一 Robert Griesemer 提交的通过 try 内置函数来简化错误处理就被否决了。失败的尝试是一个好的现象,它表示 Go 语言依然在一些新兴领域的尝试 —— Go 语言依然处于活跃期。

今年 9 月 3 号,Go 发布 1.13 版本,除了 module 特性转正之外,还改进了数字字面量。比较重要的还有 defer 性能提升 30%,将更多的对象从堆上移动到栈上以提升性能,等等。

还有一个重大的改进发生在 errors 标准库中。errors 库增加了 Is/As/Unwrap三个函数,这将用于支持错误的再次包装和识别处理,为 Go 2 中新的错误处理改进提前做准备。

1.13 支持了 error 包裹(wrapping):

An error e can wrap another error w by providing an Unwrap method that returns w. Both e and w are available to programs, allowing e to provide additional context to w or to reinterpret it while still allowing programs to make decisions based on w.

为了支持 wrapping,fmt.Errorf 增加了 %w 的格式,并且在 error 包增加了三个函数:errors.Unwrap,errors.Is,errors.As。

fmt.Errorf

使用 fmt.Errorf 加上 %w 格式符来生成一个嵌套的 error,它并没有像 pkg/errors 那样使用一个 Wrap 函数来嵌套 error,非常简洁。

Unwrap

  1. func Unwrap(err error) error 

将嵌套的 error 解析出来,多层嵌套需要调用 Unwrap 函数多次,才能获取最里层的 error。

源码如下:

  1. func Unwrap(err error) error { 
  2.  // 判断是否实现了 Unwrap 方法 
  3.     u, ok := err.(interface { 
  4.         Unwrap() error 
  5.     }) 
  6.     // 如果不是,返回 nil 
  7.     if !ok { 
  8.         return nil 
  9.     } 
  10.     // 调用 Unwrap 方法返回被嵌套的 error 
  11.     return u.Unwrap() 

对 err 进行断言,看它是否实现了 Unwrap 方法,如果是,调用它的 Unwrap 方法。否则,返回 nil。

Is

  1. func Is(err, target error) bool 

判断 err 是否和 target 是同一类型,或者 err 嵌套的 error 有没有和 target 是同一类型的,如果是,则返回 true。

源码如下:

一文悟透备受争议的 Go 语言错误处理

通过一个无限循环,使用 Unwrap 不断地将 err 里层嵌套的 error 解开,再看被解开的 error 是否实现了 Is 方法,并且调用它的 Is 方法,当两者都返回 true 的时候,整个函数返回 true。

As

  1. func As(err error, target interface{}) bool 

从 err 错误链里找到和 target 相等的并且设置 target 所指向的变量。

源码如下:

一文悟透备受争议的 Go 语言错误处理

返回 true 的条件是错误链里的 err 能被赋值到 target 所指向的变量;或者 err 实现的 As(interface{}) bool 方法返回 true。

前者,会将 err 赋给 target 所指向的变量;后者,由 As 函数提供这个功能。

如果 target 不是一个指向“实现了 error 接口的类型或者其它接口类型”的非空的指针的时候,函数会 panic。

这一部分的内容,飞雪无情大佬的文章【飞雪无情 分析 1.13 错误】写得比较好,推荐阅读。

总结

Go 语言使用 error 和 panic 处理错误和异常是一个非常好的做法,比较清晰。至于是使用 error 还是 panic,看具体的业务场景。

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读