這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
今天飯飯給我出了個題目,下面這段代碼為什麼報錯,怎麼改?
123456789101112131415161718192021222324252627 |
package mainimport ( "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} |
運行一下,發現報錯如下:
1234567 |
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 +0x280exit status 2 |
18行,也就是
報錯了,報錯沒法提供更多資訊(go新手,老鳥可能能看出端倪),我們加一些列印
123456789101112 |
func main() { var a *A fmt.Printf("%p\n", &a) // 1 if check(a) { a, err := generate() fmt.Printf("%p\n", &a) // 2 fmt.Println(a.s, err) // 3 } fmt.Printf("%p\n", &a) // 4 fmt.Println(a.s) } |
結果如下:
1234 |
0xc42000c028 // 10xc42000c038 // 2b <nil> // 30xc42000c028 // 4 |
我們發現,2處的a竟然不是我們定義的(1處)a,發生了什麼!
其實看到這裡很多人可能都明白了,其實是a, err := generate()裡面:=的問題,我們最初的設想是golang會定義新變數err,而a為初始定義的那個變數(1處)。但實際情況是,對於使用:=定義的變數,如果新變數與那個同名已定義變數 (這裡就是1處的變數a)不在一個範圍中時,那麼golang會重新定義這個變數,這就是導致這個問題的真兇。
怎麼改呢,我們重寫一下main函數:
12345678910 |
func main() { var a *A var err error if check(a) { a, err = generate() fmt.Println(a.s, err) } fmt.Println(a.s) } |
如此即可~
這個坑真的非常容易踩,而且不太好發現,感謝飯飯?