Golang 学习笔记——变量的重声明问题

今天写 Golang 代码时遇到重复声明同名变量的问题,发现这个还是挺有意思的。

这里说的重复声明不是指这种

1
2
3
x := 1
x := 2
fmt.Println(x)

这样的话肯定是不行的,会报错

1
no new variables on left side of :=

而是指像下边这样的,这个是可以正常运行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// code #1
x := 1
fmt.Println(x, &x)
x, y := 2, "???"
fmt.Println(x, &x, y)

// code #2
if x, y := 3, "!!!"; true {
fmt.Println(x, &x, y)
x := 4
fmt.Println(x, &x, y)
x, y := 5, "@@@"
fmt.Println(x, &x, y)
}
fmt.Println(x, &x, y)

输出结果类似于这样

1
2
3
4
5
6
1 0xc82000a410
2 0xc82000a410 ???
3 0xc82000a470 !!!
4 0xc82000a4a0 !!!
5 0xc82000a4a0 @@@
2 0xc82000a410 ???

这样的方式对于一个曾经主要用 Java 的人来说,感觉很诡异,因为在 Java 中类似的写法,是编译不通过的,比如下面这种

1
2
3
4
5
// java
int i = 0;
for (int i = 0; i < 10; 1++) {
// do something...
}

当然了,因为 java 中并没有类似于 Go 中:=这样的声明方式,所以这个栗子其实是不恰当的。

重新回到 Go 来说,翻阅了一下网上的资料,找到了点眉目。官方文档 https://golang.org/ref/spec 中有这么一段:

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.

翻译过来也就是

不同于常规变量声明,在相同块中且至少有一个非空白变量的短变量声明中,可对原先声明的变量以相同的类型重声明。因此,重声明只能出现在多变量的短声明中。 重声明不能生成新的变量;它只能赋予新的值给原来的变量。

这个能很好的解释code #1
不过对于code #2,却没找到相关的描述。我个人的推测是,在if的初始化子句中使用:=声明的变量xy是两个全新的变量,在if语句内的对它们的访问和赋值影响不到外边的x`y(如果在if的初始化子句中使用=赋值而不是:=声明变量,则会影响的外边xy)。 但是我还有个疑惑的地方:if语句内的第10行x := 4和第12行x, y := 5, “@@@”这两句为什么能声明成功?——只看if这个代码块的话,xy都是在该代码块已声明的变量,并不满足短变量声明的 *“:=左边需要有一个新变量”* 这个条件(如果把这两句拿到if`外边的话是编译不了的)。