Go语言中更优雅的错误处理

2020-01-28 12:04:19丽君

实际上这里 Golang 标准库中返回了一个名为 PathError 的结构体,这个结构体定义了操作类型、路径和原始的错误信息,然后通过 Error 方法对所有信息进行了整合。

但是这样也会存在问题,比如需要进行单独类型复杂的分类处理,比如上面例子中,需要单独处理 PathError 这种问题,你可能需要一个单独的类型推导:


err := xxxx()
if err != nil {
 swtich err := err.(type) {
 case *os.PathError:
 ...
 default:
 ...
 }
}

这样反倒会增加错误处理的复杂度。同时,这些错误必须变为导出类型,也会增加整个系统的复杂度。

另外一个问题是,我们在出现错误时,我们通常也希望获取更多的堆栈信息,方便我们进行后续的故障追踪。在现有的错误体系中,这相对比较复杂:你很难通过一个接口类型获取完整的调用堆栈。这时,我们可能就需要一个第三方库区去解决遇到的这些错误处理问题。

还有一种情况是,我们希望在错误处理过程中同样可以附加一些信息,这些也会相对比较麻烦。

更优雅的错误处理

之前提到了多种实际应用场景中出现的错误处理方法和遇到的一些问题,这里推荐使用第三方库去解决部分问题:github.com/pkg/errors

比如当我们出现问题时,我们可以简单的使用 errors.New 或者 errors.Errorf 生成一个错误变量:


err := errors.New("whoops")
// or
err := errors.Errorf("whoops: %s", "foo")

当我们需要附加信息时,则可以使用:


cause := errors.New("whoops")
err := errors.Wrap(cause, "oh noes")

当需要获取调用堆栈时,则可以使用:


err := errors.New("whoops")
fmt.Printf("%+v", err)

其他建议

在上面做类型推导时,我们发现在处理一类错误时可能需要多个错误类型,这可能在某些情况下相对来说比较复杂,很多时候我们可以使用接口形式去方便处理:


type temporary interface {
 Temporary() bool
}

// IsTemporary returns true if err is temporary.
func IsTemporary(err error) bool {
 te, ok := errors.Cause(err).(temporary)
 return ok && te.Temporary()
}

这样就可以提供更加方便的错误解析和处理。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。