为什么即使左侧没有定义新变量,else if 语句中的短变量声明也不会编译失败?

Lon*_*ner 4 syntax grammar go semantics

以下代码预计会在编译时失败并出现错误:

package main

import (
    "fmt"
)

func main() {
    x := 10
    x := x + 1
    fmt.Println(x)
}
Run Code Online (Sandbox Code Playgroud)

编译错误是:

./prog.go:9:4: no new variables on left side of :=
Run Code Online (Sandbox Code Playgroud)

所以我期待这段代码也会因错误而失败:

./prog.go:9:4: no new variables on left side of :=
Run Code Online (Sandbox Code Playgroud)

这是输出:

else if block: x:  11
Run Code Online (Sandbox Code Playgroud)

为什么即使:=操作符 inelse if x := x + 1没有定义任何新变量,第二个程序也会成功?

bla*_*een 14

根据 Go 规范,以下if是定义语句的方式:

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .

后来,在声明和范围部分说:

在块中声明的标识符可以在内部块中重新声明。虽然内部声明的标识符在范围内,但它表示内部声明所声明的实体。

现在,该if语句是一个隐式块

每个“if”、“for”和“switch”语句都被认为是在它自己的隐式块中。

那么从IfStmt定义中可以看出,在关键字之后else可能会出现:

  • 一个Block,即else { /* code */ }
  • 一个IfStmt再像你的情况,即else if /* statement */ { /* code */ }。这意味着IfStmt是递归的,并且它是一个隐含的块另一IfStmt(仍隐式块)。因此满足重新声明标识符的条件。

也与显式块进行比较:

func foo() {
    x := 10
    {
        x := 20
        fmt.Println("Inner x:", x) // 20
    }
    fmt.Println("Outer x:", x) // 10
}
Run Code Online (Sandbox Code Playgroud)