The following code is expected to fail with an error on compilation:
package main
import (
"fmt"
)
func main() {
x := 10
x := x + 1
fmt.Println(x)
}
The compilation error is:
./prog.go:9:4: no new variables on left side of :=
So I was expecting this code to also fail with error:
package main
import (
"fmt"
)
func main() {
if x := 10; x < 10 {
fmt.Println("if block: x:", x)
} else if x := x + 1; x < 20 {
fmt.Println("else if block: x: ", x)
}
}
Here is the output:
else if block: x: 11
Why does the second program succeed even though the :=
operator in else if x := x + 1
is not defining any new variable?
From the Go specs, here is how an if
statement is defined:
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
Later on, in the Declarations and Scope sections it is said:
An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration.
Now, the if
statement is an implicit block:
Each "if", "for", and "switch" statement is considered to be in its own implicit block.
Then as you can see from the IfStmt
definition, after the keyword else
may come:
Block
, i.e. else { /* code */ }
IfStmt
again, as in your case, i.e. else if /* statement */ { /* code */ }
. This means the IfStmt
is recursive, and it is an implicit block within another IfStmt
(still an implicit block). Therefore it meets the condition for redeclaring the identifier.Compare also with explicit blocks:
func foo() {
x := 10
{
x := 20
fmt.Println("Inner x:", x) // 20
}
fmt.Println("Outer x:", x) // 10
}