生產(chǎn)環(huán)境中遇到了一次奇怪的報錯,代碼結構大致如下所示:
type A struct {
a string
b int
}
func (a *A) foo() {
fmt.Println("foo")
}
func (a *A) bar() {
fmt.Println(a.a)
}
func main() {
var a *A
a.foo()
a.bar()
}
程序運行時,會在a.bar()處報空指針錯誤。具體時fmt.Println(a.a)的位置。
排查問題時感到比較疑惑:如果是空指針錯誤,a在調(diào)用foo()時就是空指針,為什么在a.foo()處沒有報錯?
在foo()和bar()中加入調(diào)用棧打印后,得到運行結果:
main.(*A).foo(0x0)
.../main.go:14 +0x22
main.main()
.../main.go:25 +0x2a
main.(*A).bar(0x0)
.../main.go:19 +0x26
main.main()
.../main.go:26 +0x37
panic: runtime error: invalid memory address or nil pointer dereference
這么一看就是合理的了:
foo()和bar()的入?yún)⒍际?x0,也就是空指針a。
雖然調(diào)用foo()的是空指針,但成員函數(shù)的地址在函數(shù)編譯時就確定了,所以在執(zhí)行時沒有使用到空指針。
bar()中對空指針解引用,所以會導致錯誤。
結論是: golang中結構提空指針調(diào)用它的方法,如果函數(shù)執(zhí)行過程中沒有對空指針解引用,則不會報nil pointer dereference。