一文悟透备受争议的 Go 语言错误处理(5)
使用第三方的 error 包就可以比较完美的解决问题:
返回的错误,对于人和机器而言,都是友好的。 小结 这一部分主要讲了处理 error 的一些原则,引入了第三方的 errors 包,使得错误处理变得更加优雅。 作者最后给出了一些结论:
胎死腹中的 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
将嵌套的 error 解析出来,多层嵌套需要调用 Unwrap 函数多次,才能获取最里层的 error。 源码如下:
对 err 进行断言,看它是否实现了 Unwrap 方法,如果是,调用它的 Unwrap 方法。否则,返回 nil。 Is
判断 err 是否和 target 是同一类型,或者 err 嵌套的 error 有没有和 target 是同一类型的,如果是,则返回 true。 源码如下: 通过一个无限循环,使用 Unwrap 不断地将 err 里层嵌套的 error 解开,再看被解开的 error 是否实现了 Is 方法,并且调用它的 Is 方法,当两者都返回 true 的时候,整个函数返回 true。 As
从 err 错误链里找到和 target 相等的并且设置 target 所指向的变量。 源码如下: 返回 true 的条件是错误链里的 err 能被赋值到 target 所指向的变量;或者 err 实现的 As(interface{}) bool 方法返回 true。 前者,会将 err 赋给 target 所指向的变量;后者,由 As 函数提供这个功能。 如果 target 不是一个指向“实现了 error 接口的类型或者其它接口类型”的非空的指针的时候,函数会 panic。 这一部分的内容,飞雪无情大佬的文章【飞雪无情 分析 1.13 错误】写得比较好,推荐阅读。 总结 Go 语言使用 error 和 panic 处理错误和异常是一个非常好的做法,比较清晰。至于是使用 error 还是 panic,看具体的业务场景。 (编辑:ASP站长网) |