生产环境中遇到了一次奇怪的报错,代码结构大致如下所示:
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在调用foo()时就是空指针,为什么在a.foo()处没有报错?
在foo()和bar()中加入调用栈打印后,得到运行结果:
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()的入参都是0x0,也就是空指针a。
虽然调用foo()的是空指针,但成员函数的地址在函数编译时就确定了,所以在执行时没有使用到空指针。
bar()中对空指针解引用,所以会导致错误。
结论是: golang中结构提空指针调用它的方法,如果函数执行过程中没有对空指针解引用,则不会报nil pointer dereference。