go语言作用域踩坑

Youmai の Blog · · 1092 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

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

1
fmt.Println(a.s)

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

1
2
3
4
5
6
7
8
9
10
11
12
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)
}

结果如下:

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)
}

如此即可~

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


有疑问加站长微信联系(非本文作者)

本文来自:Youmai の Blog

感谢作者:Youmai の Blog

查看原文:go语言作用域踩坑

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1092 次点击  
加入收藏 微博
1 回复  |  直到 2017-11-04 02:55:52
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传