为什么Go中可以在多个return语句中重新定义err

问题描述 投票:0回答:2

考虑下面的示例来说明问题(它只是为了解释问题而构建的,但我在书中以及实际项目中都看到了类似的代码):

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
,它会抱怨
no new variable on left side of :=

那么,它是如何运作的呢?为什么编译器乐意允许在多重返回语句中使用

err
覆盖
:=
,而不是在
n1
示例中使用
<- line 2

如果您能指出解释此行为的官方参考资料,那就更好了。

go variable-assignment
2个回答
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

它是一个多变量短声明,但是左侧的所有变量都已在同一个块中先前声明过,因此这也是一个编译时错误(它不会在上面引入任何新变量)左侧)。

请注意,如果左侧的所有变量都已预先声明,只需将短变量声明

:=
更改为 Assignment
=
即可使其工作(假设右侧的值是 可分配 给变量)在左侧)。


0
投票

查看本官方文档中的“重新声明和重新分配”部分https://go.dev/doc/ effective_go

© www.soinside.com 2019 - 2024. All rights reserved.