一个有关Golang变量作用域的坑
来源:互联网 发布:js null undefined 编辑:程序博客网 时间:2024/06/05 18:48
临近下班前编写和调试一段Golang代码,但运行结果始终与期望不符,怪异的很,下班前依旧无果。代码Demo如下:
//testpointer.go
package main
import (
"fmt"
)
var p *int
func foo() (*int, error) {
var i int = 5
return &i, nil
}
func bar() {
//use p
fmt.Println(*p)
}
func main() {
p, err := foo()
if err != nil {
fmt.Println(err)
return
}
bar()
fmt.Println(*p)
}
这段代码原意是定义一个包内全局变量p,用foo()的返回值对p进行初始化,在bar中使用p。预期结果:bar()和main()中均输出5。但编译执行后的结果却是:
$go run testpointer.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x20d1]
goroutine 1 [running]:
main.bar()
/Users/tony/Test/Go/testpointer.go:17 +0xd1
main.main()
/Users/tony/Test/Go/testpointer.go:26 +0x11c
goroutine 2 [runnable]:
runtime.forcegchelper()
/usr/local/go/src/runtime/proc.go:90
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2232 +0×1
goroutine 3 [runnable]:
runtime.bgsweep()
/usr/local/go/src/runtime/mgc0.go:82
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2232 +0×1
goroutine 4 [runnable]:
runtime.runfinq()
/usr/local/go/src/runtime/malloc.go:712
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2232 +0×1
exit status 2
晚饭后,继续调试这段代码。怎么还crash了!代码看似半点问题都没有,难道是Go编译器的问题,我用的可是最新的1.4,切换回1.3.3,问题依旧啊。看来还是代码的问题,但问题在哪里呢?加上些打印语句再看看:
func bar() {
//use p
fmt.Printf("%p, %T\n", p, p) //output: 0x14dc80, 0×0, *int
fmt.Println(*p) //Crash!!!
}
func main() {
fmt.Printf("%p, %T\n", p, p) //output: 0x14dc80, 0×0, *int
p, err := foo()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%p, %T\n", p, p) //output: 0x2081c6020, 0x20818a258, *int
bar()
fmt.Println(*p)
}
通过打印输出,发现从foo函数中返回的p(0x2081c6020)与全局变量的p(0x14dc80)居然不是一个地址,也就是说不是一个变量。而且 从bar()中的调试输出来看,全局变量p在foo函数返回时并未被赋值为foo中变量i的地址,而依然是一个nil值,从而导致程序Crash。
好了,废话不说了,该是揭晓真相的时候了。问题就在于":="。在main这个作用域中,我们使用了
p, err := foo()
最初的理解是golang会定义新变量err,p为初始定义的那个全局变量。但实际情况是,对于使用:=定义的变量,如果新变量p与那个同名已定义变量 (这里就是那个全局变量p)不在一个作用域中时,那么golang会新定义这个变量p,遮盖住全局变量p,这就是导致这个问题的真凶。
我们将main函数改为:
func main() {
var err error
p, err = foo()
if err != nil {
fmt.Println(err)
return
}
bar()
}
则执行结果就完全符合预期了。
- 一个有关Golang变量作用域的坑
- 一个有关Golang变量作用域的坑
- golang变量作用域问题
- 有关javascript的变量作用域
- golang的局部作用域和变量推导
- golang如何得到一个变量的类型
- JavaScript变量作用域的一个问题
- 一个demo看懂变量的作用域
- JS当中一个变量的作用域
- 有关作用域的知识
- Golang 的一个小坑
- 记录golang 的一个坑
- 有关js的变量作用域和this指针的讨论
- bash遇到的一个变量作用域问题,记录下
- 一个问题,关于函数嵌套后的变量作用域
- 变量的作用域
- 变量的作用域
- 变量的作用域
- CATransition完成几种动画效果
- 使用Hibernate进行大数据量的性能测试
- Android 关于判断网络的问题
- 微信企业号开发四:文件上传到微信服务器
- jquery 跳出each循环
- 一个有关Golang变量作用域的坑
- Linux的bg和fg命令简单介绍
- 多类的设计
- knock.js的subscribe使用 通过$.ajax(); $get();解析JSON数据
- [时空与飞翔]2015.12.16日 天窗打开 时空之门打开
- 数据结构和算法经典100题-第21题
- Oracle中查看所有表和字段
- Linux进程间通信——使用共享内存
- mysql 重置主键