考虑下面的示例来说明问题(它只是为了解释问题而构建的,但我在书中以及实际项目中都看到了类似的代码):
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
覆盖 :=
,而不是在 n1
示例中使用 <- line 2
?
如果您能指出解释此行为的官方参考资料,那就更好了。
这是因为你使用了短变量声明
:=
。引用规范:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初是在同一块(或参数列表,如果该块是函数体)中以相同的类型声明的,并且至少有一个非-空白变量是新的。因此,重新声明只能出现在多变量短声明中。重新声明不会引入新变量;它只是为原始值分配一个新值。
这一行:
n1, err := strconv.Atoi("1")
是一个多变量短声明,左侧的所有变量都是新的,因此都会被声明(并分配
strconv.Atoi()
的返回值)。
这一行:
n2, err := strconv.Atoi("2")
它是一个多变量简短声明,并且
n2
是新的。因此它声明了 n2
并且只为 err
分配了一个新值,因为 err
已经在同一个块中声明了。
这一行:
err := fmt.Errorf("new error") <- line 1
它不是多变量简短声明。它会尝试声明
err
但它已经在同一个块中声明,因此这是一个编译时错误。
还有这一行:
n1, err := strconv.Atoi("3") <- line 2
它是一个多变量短声明,但是左侧的所有变量都已在同一个块中先前声明过,因此这也是一个编译时错误(它不会在上面引入任何新变量)左侧)。
请注意,如果左侧的所有变量都已预先声明,只需将短变量声明
:=
更改为 Assignment =
即可使其工作(假设右侧的值是 可分配 给变量)在左侧)。
查看本官方文档中的“重新声明和重新分配”部分https://go.dev/doc/ effective_go。