工作中我們會發(fā)現(xiàn)代碼中會使用%s
格式化err的情況励稳,包括一些開源代碼佃乘。但是你翻一下源碼,內(nèi)置的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實(shí)踐能力產(chǎn)生了懷疑裸违,哈哈哈额嘿。限嫌。。不要懷疑(me too)讲逛,你是Ok的,只是go的格式化輸出做了特殊處理而已岭埠。
調(diào)用鏈路是這樣的:
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: // 重點(diǎn)在這里盏混,對error類型的參數(shù)做了特殊處理
handled = true
defer p.catchPanic(p.arg, verb, "Error")
p.fmtString(v.Error(), verb) // 調(diào)用的error.Error方法,輸出里面的字符串
return
case Stringer:
handled = true
defer p.catchPanic(p.arg, verb, "String")
p.fmtString(v.String(), verb)
return
}
}
看到這里你應(yīng)該明白了把枫攀。但是需要說明一下括饶,如果有些log庫自己實(shí)現(xiàn)了格式化邏輯,那么你就要具體情況具體分析了来涨。