考虑下面的例子来说明这个问题(它只是为了解释这个问题而构建的,但我在书中和真实的项目中看到了类似的代码):
package main
import (
"strconv"
"fmt"
"log"
)
func main() {
n1, err := strconv.Atoi("1")
if err != nil {
log.Panicf("%v", err)
}
n2, err := strconv.Atoi("2")
if err != nil {
log.Panicf("%v", err)
}
// err := fmt.Errorf("new error") <- line 1
// n1, err := strconv.Atoi("3") <- line 2
fmt.Printf("n1 = %d, n2 = %d\n", n1, n2)
}
编译器不会抱怨重新定义err
,但是如果我取消注解<- line 1
或<- line 2
,它会抱怨no new variable on left side of :=
。
那么,它是如何工作的呢?为什么编译器很高兴地允许在多返回语句中覆盖err
,使用:=
,而不是<- line 2
示例中的n1
?
如果你能指出解释这种行为的官方参考,那就更好了。
2条答案
按热度按时间mklgxw1f1#
这是因为你使用了短变量声明
:=
。引用规范:与常规变量声明不同,短变量声明可以 * 重新声明 * 变量,前提是它们最初在同一块(或参数列表,如果块是函数体)中以相同类型声明,并且至少有一个非空变量是新的。因此,redeclaration只能出现在多变量短声明中。重新声明不会引入新变量;它只会给原来的值赋一个新值
这一行:
是一个多变量短声明,左边的所有变量都是新的,因此所有变量都将被声明(并返回赋值的
strconv.Atoi()
值)。这一行:
它是一个多变量短声明,
n2
是新的。所以它声明了n2
,只给err
赋值,因为err
已经在同一个块中声明了。这一行:
它是不是多变量短声明。它会尝试声明
err
,但它已经在同一个块中声明了,因此这是一个编译时错误。这一行
这是一个多变量短声明,但是左边的所有变量都已经在同一个块中声明过,所以这也是一个编译时错误(它没有在左边引入任何新变量)。
请注意,如果左侧的所有变量都已经声明过,只需将Short变量声明
:=
更改为Assignment=
即可使其工作(假设右侧的值可以分配给左侧的变量)。eoigrqb62#
检查本官方文件https://go.dev/doc/effective_go中的“重新声明和重新分配”一节。