为什么在Go语言中可以在多个返回语句中重新定义err?

huangapple go评论90阅读模式
英文:

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 (
	&quot;strconv&quot;
	&quot;fmt&quot;
	&quot;log&quot;
)

func main() {
	n1, err := strconv.Atoi(&quot;1&quot;)
	if err != nil {
		log.Panicf(&quot;%v&quot;, err)
	}

	n2, err := strconv.Atoi(&quot;2&quot;)
	if err != nil {
		log.Panicf(&quot;%v&quot;, err)
	}

    // err := fmt.Errorf(&quot;new error&quot;) &lt;- line 1

	// n1, err := strconv.Atoi(&quot;3&quot;) &lt;- line 2

	fmt.Printf(&quot;n1 = %d, n2 = %d\n&quot;, n1, n2)
}

The compiler doesn't complain about redefining err, but if I uncomment &lt;- line 1 or &lt;- 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 &lt;- 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(&quot;1&quot;)

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(&quot;2&quot;)

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(&quot;new error&quot;) &lt;- 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(&quot;3&quot;) &lt;- 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).

huangapple
  • 本文由 发表于 2015年12月14日 19:50:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/34266337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定