On Monday we saw how to create explicit code blocks in Go. Now we’ll breeze through the list of implicit code blocks that exist.
Blocks
…
In addition to explicit blocks in the source code, there are implicit blocks:
- The universe block encompasses all Go source text.
- Each package has a package block containing all Go source text for that package.
- Each file has a file block containing all Go source text in that file.
- Each “if”, “for”, and “switch” statement is considered to be in its own implicit block.
- Each clause in a “switch” or “select” statement acts as an implicit block.
Blocks nest and influence scoping.
Starting tomorrow, we’ll talk about scoping, where most of this starts to make more sense. But for today I want to call out one of these implicit scoping rules that’s a bit suprising to some.
Number 4 says that “Each ‘if’ … is considered to be its own implicit block.”
This seems intuitive enough at first…
if x := foo(); x > 3 {
fmt.Printf("x = %v\n", x)
}
The variable x
is accessible within the body of the if
statement, because its declaration happens with the simple statement (a concept we’ll get to) in the if statement.
What’s not as obvious is that this implicit scope actually extends to any else
or else if
clauses of the same if statement:
if x := foo(); x > 3 {
fmt.Printf("x = %v\n", x)
return
} else if x < 0 {
fmt.Println("x is too small", x)
return
} else {
fmt.Println("x is just right", x)
return
}
Notice that the x
variable is accessible within the else if
and else
blocks as well. But if we rewrite this code, as below, we lose that scoping, and x
is undefined:
if x := foo(); x > 3 {
fmt.Printf("x = %v\n", x)
return
}
if x < 0 { // x is not defined
fmt.Println("x is too small", x)
return
}
fmt.Println("x is just right", x) // x is not defined
return
To make this code work without the else
s, we have to pull x
’s assignment out of the implicit if block:
x := foo() // x is defined outside of the implicit if block
if x > 3 {
fmt.Printf("x = %v\n", x)
return
}
if x < 0 {
fmt.Println("x is too small", x)
return
}
fmt.Println("x is just right", x)
return
Quotes from The Go Programming Language Specification Version of December 15, 2022