Sentinel Error
预定义的特定错误,我们称之为sentinel error
,这个名字来源于计算机编程中使用一个特定值来表示不可能进行进一步处理的做法。所以对于Go,我们使用特定的值来表示错误。
if err == ErrSomething{...}
类似的io.EOF
,更底层的syscall.ENOENT
。
使用sentinel值是最不灵活的错误处理策略,因为调用方必须使用 == 讲结果于预先声明的值进行比较。当使用者想要提供更多的是上下文时,就会出现一个问题:返回一个不同的错误讲破坏相等性检查。
甚至是一些有意义的fmt.Errorf 携带一些上下文,也会破坏调用者的 == ,调用者将被迫查看error.Error()方法的输出,以查看她是否与特定的字符串匹配。
- 不依赖检查
error.Error
的输出。
不应该以来检测 error.Error的输出,Error 方法存在于error 接口主要用于方便程序员使用,但不是程序(编写测试可能会以来这个返回)。这个输出的字符串用于记录日志、输出到stdout
-
Sentinel errors
成为你API公共部分如果您的公共函数或方法返回一个特定值的错误,那么该值必须是公共的,要有文档记录,这是增加API的表面积。
如果API定义了一个返回特定错误的
interface
,则该接口的所有实现都讲被限制为仅返回该错误,即使他们可以提供更具描述性的错误。比如
io.Reader
。像io.Copy
这类函数需要reader
的实现者比如返回io.EOF
来告诉调用者没有更多数据了,但这个又不是错误。 -
Sentinel errors
在两个包之间创建了依赖sentinel errors
最糟糕的问题是它们在两个包之间创建了源代码依赖关系。例如,检查错误是否等于io.EOF
,那么您的代码必须导入io
包。这个特定的例子看起来并不是很糟,因为其非常常见,但是想象一下,当项目中的许多包导出错误值时,存在耦合,项目中的其他包必须导入这些错误值才能检查特定的错误条件(in the form of an import loop
)。 -
结论:尽可能避免
sentinel errors
。建议在代码编写中避免使用
sentinel errors
。在标准库中有一些使用它们的情况,但这不是我们应该模仿的模式。
Error types
Error types
是实现了error
接口的自定义类型。例如MyError
类型记录了文件和行号以展示发生了什么。
因为MyError
是一个type
,调用者可以使用断言转换成这个类型,来获取更多的上下文信息。
package main
import (
"fmt"
)
type MyError struct {
Msg string
File string
Line int
}
// 只要