您所经历的通常称为 “可变阴影”
。当您使用
:=在内部范围内的任何变量,包括像语句
if和
for尽管缺乏支撑的,一个新的类型和值与该变量关联:
n := "Example"//Prints the string variable `n` to standard output and// returns the number of bytes written in int variable `n` and// an error indicator in error variable `err`.if n, err := fmt.Println(n); err != nil { panic(err)} else { fmt.Println(n, "bytes written")}//Prints the string variable `n` to standard output.fmt.Printf("n = %qn", n)输出:
Example8 bytes writtenn = "Example"
有几种解决此问题的方法:
- 在使用变量之前声明您需要的变量,并使用常规赋值
=
- 使用不同的变量名
- 创建一个新的作用域并保存变量的值以供以后访问,根据需要使用变量名
:=
,并在作用域结束之前恢复该值;通常,仅使用不同的变量名会更容易,因为无论如何您都在创建另一个变量
当您在内部范围中声明某些内容却没有意识到时,也会发生相反的效果:
if _, err := fmt.Println(n); err != nil { panic(err)} else { fmt.Println(n, "bytes written")}//undefined: errif _, err = fmt.Println(n); err != nil { //undefined: err panic(err)}同样,有几种不同的方法可以解决此问题:
- 在使用变量之前声明您需要的变量,并使用常规赋值
=
- 将first
:=
和if
statement 分开,以便按预期声明变量;这使您可以=
在该范围以及包含该范围的任何范围的上下文中使用该变量的所有其他实例 - 改变的所有实例
=
,以:=
修正错误
请注意,当函数返回多个值时,在后两种情况中的任何一种情况下,您都可能会遇到变量阴影问题,但是可以如上所述解决。
在Go Playground上尝试两个示例。
最后一个示例说明了声明和初始化新变量,
b同时还为现有变量分配值的组合
a。没有创建新的作用域,因此您不会隐藏原始变量
a,可以通过
a在每次赋值之后(但在下一个声明/赋值之前)打印的地址来进行验证:
a := 1fmt.Println(&a)a, b := 2, 3fmt.Println(&a)a = b // avoids a "declared but not used" error for `b`
当然,如果您没有声明
b,那么您将收到编译器的错误消息,即
:=第二个声明的左侧没有新变量,这是您尝试声明的一种a回方式。
a在同一范围内两次。
请注意,如果仔细应用此想法,也可用于查找阴影变量。例如,您的示例中的“不起作用”代码将为打印不同的地址
a,具体取决于
a内部作用域是否已声明:
a := 1{ fmt.Println(&a) // original `a` a, b := 2, 3 fmt.Println(&a) // new `a` a = b // avoids a "declared but not used" error for `b`}fmt.Println(&a) // original `a`


