125

go语言作用域踩坑 | Youmai の Blog

 6 years ago
source link: http://michaelyou.github.io/2017/11/03/go-scope/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

go语言作用域踩坑

2017-11-03

| go

今天饭饭给我出了个题目,下面这段代码为什么报错,怎么改?

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

运行一下,发现报错如下:

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行,也就是

fmt.Println(a.s)

报错了,报错没法提供更多信息(go新手,老鸟可能能看出端倪),我们加一些打印

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)

结果如下:

0xc42000c028 // 1
0xc42000c038 // 2
b <nil> // 3
0xc42000c028 // 4

我们发现,2处的a竟然不是我们定义的(1处)a,发生了什么!

其实看到这里很多人可能都明白了,其实是a, err := generate()里面:=的问题,我们最初的设想是golang会定义新变量err,而a为初始定义的那个变量(1处)。但实际情况是,对于使用:=定义的变量,如果新变量与那个同名已定义变量 (这里就是1处的变量a)不在一个作用域中时,那么golang会重新定义这个变量,这就是导致这个问题的真凶。

怎么改呢,我们重写一下main函数:

func main() {
var a *A
var err error
if check(a) {
a, err = generate()
fmt.Println(a.s, err)
fmt.Println(a.s)

如此即可~

这个坑真的非常容易踩,而且不太好发现,感谢饭饭🙏


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK