一文悟透备受争议的 Go 语言错误处理(3)
譬如下面这段伪代码:
作为调用者,调用完 Foo 函数后,只用知道 Foo 是正常工作还是出了问题。也就是说你只需要判断 err 是否为空,如果不为空,就直接返回错误。否则,继续后面的正常流程,不需要知道 err 到底是什么。 这就是处理 Opaque errors 这种类型错误的策略。 当然,在某些情况下,这样做并不够用。例如,在一个网络请求中,需要调用者判断返回的错误类型,以此来决定是否重试。这种情况下,作者给出了一种方法:
就是说,不去判断错误的类型到底是什么,而是去判断错误是否具有某种行为,或者说实现了某个接口。 来个例子: type temporary interface { Temporary() bool}func IsTemporary(err error) bool { te, ok := err.(temporary) return ok && te.Temporary()} 拿到网络请求返回的 error 后,调用 IsTemporary 函数,如果返回 true,那就重试。 这么做的好处是在进行网络请求的包里,不需要 import 引用定义错误的包。 handle not just check errors 这一节要说第二句箴言:“Don’t just check errors, handle them gracefully”。
上面这个例子中的代码是有问题的,直接优化成一句就可以了:
还有其他的问题,在函数调用链的最顶层,我们得到的错误可能是:No such file or directory。 这个错误反馈的信息太少了,不知道文件名、路径、行号等等。 尝试改进一下,增加一点上下文:
这种做法实际上是先错误转换成字符串,再拼接另一个字符串,最后,再通过 fmt.Errorf 转换成错误。这样做破坏了相等性检测,即我们无法判断错误是否是一种预先定义好的错误了。 应对方案是使用第三方库:github.com/pkg/errors。提供了友好的界面:
通过 Wrap 可以将一个错误,加上一个字符串,“包装”成一个新的错误;通过 Cause 则可以进行相反的操作,将里层的错误还原。 有了这两个函数,就方便很多:
这是一个读文件的函数,先尝试打开文件,如果出错,则返回一个附加上了 “open failed” 的错误信息;之后,尝试读文件,如果出错,则返回一个附加上了 “read failed” 的错误。 (编辑:ASP站长网) |