Golang混合分配和声明 [英] Golang mixed assignment and declaration

查看:164
本文介绍了Golang混合分配和声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始和go一起工作了几个星期,(再一次)我偶然发现了对我来说似乎很奇怪的东西:

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

游乐场

我想同时分配两个变量. 已经声明了一个,在高级范围内,另一个没有声明.

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.

那是为什么?

推荐答案

您遇到的事情通常称为 可变阴影" .当您将:=与内部作用域中的任何变量一起使用时,即使在缺少括号的情况下,在诸如iffor之类的语句中使用时,该变量也会关联新的值和类型:

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

输出:

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:

  • 在使用它们之前声明所需的变量,并在=
  • 中使用常规赋值
  • 将第一个:=if语句分开,因此该变量被声明为预期变量;这样,您就可以在该作用域和包含该作用域的所有作用域的上下文中,对该变量的所有其他实例使用=
  • =的所有实例更改为:=以修复错误
  • 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.

在Go Playground上尝试两个示例.

您的最后一个示例说明了声明和初始化新变量b的组合,同时还为现有变量a分配了一个值.没有创建新的作用域,因此您不会隐藏原始变量a,可以通过打印进行验证a在每次分配后(但在下一个声明/分配之前)的地址:

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`

当然,如果您没有声明b,那么您将收到来自编译器的错误消息,即第二个声明的:=左侧没有新变量,这是一种绕行方式说您试图在同一范围内两次声明a.

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.

请注意,如果仔细应用此想法,也可用于查找阴影变量.例如,示例中的无效"代码会a ,具体取决于内部作用域内部的a是否已声明:

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`

这篇关于Golang混合分配和声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆