【问题标题】:err value disappearing outside of if statement错误值在 if 语句之外消失
【发布时间】:2018-09-18 17:47:55
【问题描述】:

我有以下代码:

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

if dataMap.User ... 内部的Println 打印"unauthorized",而最后一个Println 始终打印nil

我不知道为什么会这样,err 在这个函数的开头是通过var err error 声明的。

【问题讨论】:

    标签: variables go scope


    【解决方案1】:

    原因详见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?

    【讨论】:

      【解决方案2】:

      您在块内创建了err,但在块外打印相同。在块外声明错误并在打印时获取值的任何地方初始化它。

      var err error
      fmt.Println(err) // always prints nil
      

      【讨论】:

      • 这可能会导致编译错误undefined body
      • 哦,我错误地删除了 body 的赋值运算符。主要目的是在块外声明错误
      • 但这现在与原始问题有相同的阴影问题...我会声明主体(根据需要在块内部或外部)并使用赋值(=)重新定义在块外声明的错误。
      • 使用赋值运算符你正在初始化 err 的值,如果你想在正文中打印错误,你必须在块内打印它,因为它在正文外会有不同的值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多