dongqiao1158 2016-05-20 16:01
浏览 1154
已采纳

Golang混合分配和声明

I started working with go for a few weeks, and (once again) I stumbled across something that seems odd for me:

// Not working
a := 1
{
    a, b := 2, 3
}

// Works
a := 1
a, b := 2, 3

playground

I want to assign two variables simultaneously. One is already declared, in a superior scope, the other one is not.

It does not work: the compiler tries to redeclare the former variable. However, it works fine if this variable is declared in the same scope.

Why is that ?

  • 写回答

3条回答 默认 最新

  • dongyijing2353 2016-05-21 04:42
    关注

    What you're experiencing is commonly known as "variable shadowing". When you use := with any variable in an inner scope, including in statements like if and for despite the lack of braces, a new value and type are associated with that variable:

    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 = %q
    ", n)
    

    Output:

    Example
    8 bytes written
    n = "Example"
    

    There are a few different ways to fix the issue:

    • declare the variables you need before they're used and use normal assignment with =
    • use different variable names
    • create a new scope and save the variable's value for later access, use the variable name with := as you wanted, and before the scope ends, restore the value; it's normally easier to just use different variable names since you're creating another variable anyway

    The opposite effect can also occur, where you declare something in an inner scope and don't realize it:

    if _, err := fmt.Println(n); err != nil {
        panic(err)
    } else {
        fmt.Println(n, "bytes written")
    }
    
    //undefined: err
    if _, err = fmt.Println(n); err != nil {
        //undefined: err
        panic(err)
    }
    

    There are, again, a few different ways to fix this issue:

    • declare the variables you need before they're used and use normal assignment with =
    • separate the first := and if statement, so the variable is declared as intended; this allows you to use = for all other instances of that variable in the context of that scope and any scopes in which it's enclosed
    • change all instances of = to := to fix the error

    Note that you may encounter the variable shadowing issue in any of the last two cases when a function returns multiple values, but that can be resolved as explained above.

    Try both examples on the Go Playground.

    Your last example illustrates the combination of declaring and initializing a new variable b while also assigning a value to the existing variable a. No new scope is created, so you're not shadowing the original variable a, which you can verify by printing the address of a after each assignment (but before the next declaration/assignment):

    a := 1
    fmt.Println(&a)
    a, b := 2, 3
    fmt.Println(&a)
    a = b          // avoids a "declared but not used" error for `b`
    

    Of course, if you didn't declare b, then you'd receive an error from the compiler that there are no new variables on the left side of := for the second declaration, which is a roundabout way of saying that you're trying to declare a twice in the same scope.

    Note that this idea, if applied carefully, can also be used to find variables that are shadowed. For example, the "not working" code in your example would print different addresses for a, depending on whether the a inside the inner scope has been declared yet or not:

    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`
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度