英文:
Why it is possible to redefine err in multiple return statement in Go
问题
考虑以下示例来说明这个问题(它只是用来解释问题的,但我在书籍和实际项目中也看到了类似的代码):
package main
import (
"strconv"
"fmt"
"log"
)
func main() {
n1, err := strconv.Atoi("1")
if err != nil {
log.Panicf("%v", err)
}
n2, err := strconv.Atoi("2")
if err != nil {
log.Panicf("%v", err)
}
// err := fmt.Errorf("new error") <- line 1
// n1, err := strconv.Atoi("3") <- line 2
fmt.Printf("n1 = %d, n2 = %d\n", n1, n2)
}
编译器不会对重新定义的err
发出警告,但如果我取消注释<- line 1
或<- line 2
,它会报错:=
左边没有新变量。
那么,它是如何工作的?为什么编译器可以愉快地使用:=
在多返回语句中覆盖err
,但不能在<- line 2
的例子中覆盖n1
?
如果你能指出官方参考文档中解释这种行为的部分,那就更好了。
英文:
Consider the following example illustrating the question (it was just built to explain the question, but I saw similar code in books as well in real projects):
package main
import (
"strconv"
"fmt"
"log"
)
func main() {
n1, err := strconv.Atoi("1")
if err != nil {
log.Panicf("%v", err)
}
n2, err := strconv.Atoi("2")
if err != nil {
log.Panicf("%v", err)
}
// err := fmt.Errorf("new error") <- line 1
// n1, err := strconv.Atoi("3") <- line 2
fmt.Printf("n1 = %d, n2 = %d\n", n1, n2)
}
The compiler doesn't complain about redefining err
, but if I uncomment <- line 1
or <- line 2
, it will complain no new variable on left side of :=
.
So, how does it work? Why the compiler happily allows to override err
in multi return statement, using :=
, but not n1
on <- line 2
example?
Better if you can point into the official reference explaining this behavior.
答案1
得分: 26
这是因为你使用了短变量声明的 :=
。引用规范中的说明:
> 与常规变量声明不同,短变量声明可以对变量进行_重新声明_,前提是它们在同一代码块中(或者如果代码块是函数体,则在参数列表中)最初已经声明过,并且至少有一个非空白标识符是新的。因此,重新声明只能出现在多变量的短变量声明中。重新声明不会引入新的变量;它只是给原始变量赋予一个新值。
这行代码:
n1, err := strconv.Atoi("1")
是一个多变量的短变量声明,左侧的所有变量都是新的,因此它们都会被声明(并且strconv.Atoi()
的返回值会被赋值)。
这行代码:
n2, err := strconv.Atoi("2")
也是一个多变量的短变量声明,n2
是新的变量。所以它声明了n2
并且只给err
赋了一个新值,因为err
已经在同一代码块中声明过了。
这行代码:
err := fmt.Errorf("new error") <- line 1
不是一个多变量的短变量声明。它会尝试声明err
,但是它已经在同一代码块中声明过了,因此这是一个编译时错误。
还有这行代码:
n1, err := strconv.Atoi("3") <- line 2
它是一个多变量的短变量声明,但是左侧的所有变量都已经在同一代码块中先前声明过了,所以它也是一个编译时错误(它没有在左侧引入任何新的变量)。
请注意,如果左侧的所有变量都已经先前声明过了,只需将短变量声明的 :=
改为赋值的 =
就可以使其正常工作(假设右侧的值可以赋值给左侧的变量)。
英文:
It is because you used Short variable declaration :=
. Quoting from the spec:
> Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
This line:
n1, err := strconv.Atoi("1")
Is a multi-variable short declaration, and all variables on the left side are new, and so all will be declared (and return values of strconv.Atoi()
assigned).
This line:
n2, err := strconv.Atoi("2")
It is a multi-variable short declaration, and n2
is new. So it declares n2
and only assigns a new value to err
, because err
is already declared in the same block.
This line:
err := fmt.Errorf("new error") <- line 1
It is not a multi-variable short declaration. It would try to declare err
but it is already declared in the same block, therefore it is a compile-time error.
And this line:
n1, err := strconv.Atoi("3") <- line 2
It is a multi-variable short declaration, but all the variables on the left side have been previously declared in the same block, so it is also a compile-time error (it doesn't introduce any new variables on the left side).
Note that if all the variables on the left side have been previously declared, simply changing from Short variable declaration :=
to Assignment =
will make it work (assumed values on the right side are assignable to the variables on the left side).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论