今天饭饭给我出了个题目,下面这段代码为什么报错,怎么改?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main import ( "fmt" ) type A struct { s string } func main() { var a *A if check(a) { a, err := generate() fmt.Println(a.s, err) } fmt.Println(a.s) } func generate() (*A, error) { return &A{s: "b"}, nil } func check(a *A) bool { return true }
|
运行一下,发现报错如下:
1 2 3 4 5 6 7
| panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1095520] goroutine 1 [running]: main.main() /go_code/src/go_examples/go_scope.go:18 +0x280 exit status 2
|
18行,也就是
报错了,报错没法提供更多信息(go新手,老鸟可能能看出端倪),我们加一些打印
1 2 3 4 5 6 7 8 9 10 11 12
| func main() { var a *A fmt.Printf("%p\n", &a) if check(a) { a, err := generate() fmt.Printf("%p\n", &a) fmt.Println(a.s, err) } fmt.Printf("%p\n", &a) fmt.Println(a.s) }
|
结果如下:
1 2 3 4
| 0xc42000c028 // 1 0xc42000c038 // 2 b <nil> // 3 0xc42000c028 // 4
|
我们发现,2处的a
竟然不是我们定义的(1处)a
,发生了什么!
其实看到这里很多人可能都明白了,其实是a, err := generate()
里面:=
的问题,我们最初的设想是golang会定义新变量err
,而a
为初始定义的那个变量(1处)。但实际情况是,对于使用:=
定义的变量,如果新变量与那个同名已定义变量 (这里就是1处的变量a
)不在一个作用域中时,那么golang会重新定义这个变量,这就是导致这个问题的真凶。
怎么改呢,我们重写一下main
函数:
1 2 3 4 5 6 7 8 9 10
| func main() { var a *A var err error if check(a) { a, err = generate() fmt.Println(a.s, err) } fmt.Println(a.s) }
|
如此即可~
这个坑真的非常容易踩,而且不太好发现,感谢饭饭?