Content #
github.com/pkg/errors 是怎么实现输出错误信息和堆栈信息的呢?
它利用了 fmt 包的一个特性。fmt 包在打印 error 之前会判断当前打印的对象是否实现了 Formatter 接口,这个 formatter 接口只有一个 format 方法。如果要输出的对象实现了这个 Formatter 接口,则调用对象的 Format 方法来打印信息:
type Formatter interface {
Format(f State, c rune)
}
而 github.com/pkg/errors 中提供的各种初始化 error 方法(包括 errors.New)封装了一个 fundamental 结构,这个结构就是实现了 Formatter 接口:
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
这个 fundamental 结构中带着 error 的信息和堆栈信息。并且实现了 Format 方法。在 Format 方法中,判断调用 fmt.Printf 函数的第一个参数,如果是 +v,则打印错误内容和堆栈信息,如果是 v 或者 s,则打印错误内容,如果是 q,则打印转义后的信息:
func (f *fundamental) Format(s fmt.State, verb rune){
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
所以说,我们在实际的工作项目中,我建议你尽量使用 pkg/errors 而不是官方 error 库,这样我们能在错误出现的时候获取更多的错误信息,更快地定位问题。