场景一
package main
func main() {
a := 1
println(&a)
a, b := 2, true
println(b)
println(&a)
}
/** 结果
0xc000085f48
true
0xc000085f48
*/
分析:由于在相同的命名空间下,a, b := 1, true
中的变量a
并没有覆盖掉之前定义的a
变量,仅仅是创建了变量b
。如果将b
换成_
,上面的代码会报:=
没有新变量产生的错误,也可佐证。
场景二
package main
func main() {
a := 1
if a, b := 2, true; b {
println(&a)
}
println(&a)
}
/** 结果
0xc00008bf40
0xc00008bf48
*/
分析:因为if
是一个新的命名空间,因此if
语句中的变量a
覆盖的外层命名空间的a
变量。此外,if
语句内部也是独立的命令空间。
场景三
package main
var a = 1
func main() {
println(&a)
a, _ := 2, true
println(&a)
}
/** 结果
0x80f230
0xc000085f48
*/
分析:全局变量和函数也是两个命名空间,main
函数中的变量a
覆盖了全局变量a
。注意到此时的代码没有报错,也说明了main
函数中的a
是一个新的变量。
另外,此次两个a
变量的地址差别也很大。这是因为全局变量在程序的数据段,而局部变量在栈中分配。
总结
说了这么多有什么用呢?
其实与go语言对error
的处理方式有关,if
的新语法,短变量定义,多返回值都有部分原因是为了处理error
更方便。
package main
func main() {
a, err := testA()
if err != nil {
//handle error
}
if b, err := testB(); err == nil {
//handle success
}
}
短变量声明可以减少变量声明的代码,但是使用的时候也要注意被赋值的变量是不是你想要的那个变量。特别是变量在别处已经声明过的情况,可能你在定义一个新变量,而不是给变量赋值。
对于以上三个场景,总结起来就是对于:=
如果变量在同命名空间下已声明过,则不会产生新变量;否则都会产生新变量。