考虑以下示例来说明问题(它只是为解释问题而构建的,但我在书中也看到了类似的代码以及实际项目):
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 :=
。
那么,它是如何运作的?为什么编译器允许在{return返回语句中使用err
,而不是:=
上的n1
覆盖<- line 2
?
如果你能指出解释这种行为的官方参考,那就更好了。
答案 0 :(得分:12)
这是因为您使用了Short variable declaration :=
。引用规范:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初在相同的块中声明(或者如果块是函数体的参数列表),它们具有相同的类型,并且至少有一个非blank变量是新的。因此,重新声明只能出现在多变量简短声明中。重新声明不会引入新变量;它只是为原始版本赋予了一个新值。
这一行:
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 =
即可使其正常工作(假设值位于右侧)一边是assignable左侧的变量。)