Golang 混合赋值和声明 [英] Golang mixed assignment and declaration

查看:27
本文介绍了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)

输出:

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天全站免登陆