我有以下代码:
if err == nil {
body, err := ioutil.ReadAll(response.Body)
if err == nil {
dataMap := &models.UserResponse{}
json.Unmarshal(body, &dataMap)
if dataMap.User == (models.UserId{}) {
err = fmt.Errorf("unauthorized")
fmt.Println(err) // when unathorized, prints unauthorized
}
}
}
fmt.Println(err) // always prints nil
Println
内if dataMap.User ...
打印"unauthorized"
,而最后Println
始终打印nil
。
我不知道为什么会这样,err
在此函数的开头通过var err error
声明。
答案 0 :(得分:7)
原因详见Spec: Short variable declaration:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初在同一块中声明(或者如果块是函数体的参数列表)具有相同的类型,并且至少有一个非空白变量是新的。因此,重新声明只能出现在多变量简短声明中。重新声明不会引入新变量;它只是为原始版本赋予了一个新值。
当使用包含多个变量的短变量声明时,如果在同一个块中声明了,则只会对现有变量进行赋值。由于在err
块之前存在if
变量,将在err
块内创建一个新的if
变量,其中没有任何内容处理“局外人”err
变量(除了共享其名称)。在短变量声明之后,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?
答案 1 :(得分:-1)
您已在块内创建err
,但您在块外打印相同内容。在块之外声明错误并在其中的任何位置初始化它将在打印时获取值。
var err error
fmt.Println(err) // always prints nil