Go 语言中有两种变量声明的方式,其中一种就是短声明,你在使用短声明时有过以下疑惑吗?

Part1 重复定义 err

变量声明和变量定义在 C 语言中是两个不同的概念,但在 Go 语言中并没有特别区分这两个概念,因此后面用“定义”统一代指声明和定义的过程。

短声明是 Go 语言中非常方便的变量声明方式,但初次使用时我曾碰到以下的疑惑:

1
2
3
4
5
6
7
8
9
10
11
12
13
func HandleSomething() error {
data1, err := func1()
if err != nil {
fmt.Println(err)
}

...

data2, err := func2()
if err != nil {
fmt.Println(err)
}
}

这里第9行中的err难道不是重复定义吗?相信从其它语言转到 Go 语言的开发者第一次遇到这种情况都会有同样的困惑。

其实,短声明:=并不会重新定义所有左侧的变量,而是重新定义左侧需要定义的变量。

因此,短声明左侧至少要有一个新的变量,否则静态检查会报错。

在上述的例子中,第9行的短声明只是新定义了data2而已。

Part2 新作用域会定义新变量

在了解了短声明的工作方式后,我以为我已经掌握了它的用法,谁知道没过多久又踩了一个坑。

1
2
3
4
5
6
7
var res string

if true {
res, err := func3()
}

func4(res)

当我满心欢喜的想要在func4中处理res的值时,却发现res根本没有被赋值。

原来,短声明总是会在当前作用域创建新的变量。

在上述例子中,第4行中的短声明位于if的控制块中,属于新的作用域。

因此,上述代码并不是像我想的那样,使用第1行中定义的res变量,而是会定义新的res变量,新变量是if代码块中的局部变量。

如果想使用外部作用域定义的res变量,最好改成如下形式。

1
2
3
4
5
6
7
8
var res string

if true {
var err error
res, err = func3()
}

func4(res)

相关链接