工作中我们会发现代码中会使用%s
格式化err的情况,包括一些开源代码。但是你翻一下源码,内置的error接口里面,并没有String() string方法呀,怎么可能正常地打印error信息呢。
下面是一段代码示例:
err := errors.New("error test")
fmt.Printf("%s\n", err)
log.Printf("%s\n", err)
// output:
// error test
// 2022/08/02 11:00:30 error test
是不是觉得很奇怪,对自己的Go实践能力产生了怀疑,哈哈哈。。。不要怀疑(me too),你是Ok的,只是go的格式化输出做了特殊处理而已。
调用链路是这样的:
fmt.Printf -> fmt.Fprintf -> *pp.doPrintf -> *pp.printArg -> *pp.handleMethods
switch verb {
case 'v', 's', 'x', 'X', 'q':
// Is it an error or Stringer?
// The duplication in the bodies is necessary:
// setting handled and deferring catchPanic
// must happen before calling the method.
switch v := p.arg.(type) {
case error: // 重点在这里,对error类型的参数做了特殊处理
handled = true
defer p.catchPanic(p.arg, verb, "Error")
p.fmtString(v.Error(), verb) // 调用的error.Error方法,输出里面的字符串
return
case Stringer:
handled = true
defer p.catchPanic(p.arg, verb, "String")
p.fmtString(v.String(), verb)
return
}
}
看到这里你应该明白了把。但是需要说明一下,如果有些log库自己实现了格式化逻辑,那么你就要具体情况具体分析了。