原因详见Spec: Short variable declaration:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初在在同一个块中(或参数列表,如果块是函数体)具有相同的类型,并且至少有一个非空白变量是新的。因此,重新声明只能出现在多变量短声明中。重新声明不引入新变量;它只是为原始值分配一个新值。
当对已经存在的多个变量使用短变量声明时,只有在在同一个块中声明的现有变量才会发生赋值。由于在您的情况下,err 变量存在于 if 块之前,将在 if 块内创建一个新的 err 变量,这与“局外人”@ 无关987654329@ 变量(除了共享其名称)。外部err 将在短变量声明之后的if 块中隐藏。
所以发生的情况是,在 if 内部,您创建了一个新的 err 变量,并为其分配了一个值,然后将其打印出来。
在if 语句之后,您将打印外部err 变量,其值在if 块内未更改,因此它仍然是nil。
看这个例子:
var err error
fmt.Println("outside:", err) // nil
{
// A new err variable, shadows the outer:
i, err := strconv.Atoi("a")
fmt.Println("inside:", i, err) // 0 strconv.Aoti: parsing "a": invalid syntax
}
fmt.Println("outside:", err) // nil, because this was never changed
// Now this will change the "outer" err:
j, err := strconv.Atoi("a")
fmt.Println("outside:", j, err) // 0 strconv.Aoti: parsing "a": invalid syntax
输出(在Go Playground上试试):
outside: <nil>
inside: 0 strconv.Atoi: parsing "a": invalid syntax
outside: <nil>
outside: 0 strconv.Atoi: parsing "a": invalid syntax
如果您想在创建新变量时使用(分配给)“外部”变量,则不能在“嵌套”块中使用短变量声明,而只能使用简单分配,在这种情况下,您还必须先验地声明其他变量,如下例所示:
if err == nil {
var body []byte
body, err = ioutil.ReadAll(response.Body)
// ... rest...
}
查看相关问题:
Why it is possible to redefine err in multiple return statement in Go
Why there are two ways of declaring variables in Go, what's the difference and which to use?