This post is about declaration scopes and shadowing in Go.
package main import "fmt" func f(x int) { for x := 0; x < 10; x++ { fmt.Println(x) } } var x int func main() { var x = 200 f(x) }
This program declares x
four times. All four are different variables because they exist in different scopes.
package main import "fmt" func f() { x := 200 fmt.Println("inside f: x =", x) } func main() { x := 100 fmt.Println("inside main: x =", x) f() fmt.Println("inside main: x =", x) }
In Go the scope of a declaration is bound to the closest pair of curly braces, {
and }
. In this example, we declare x
to be 100 inside main, and 200 inside f
.
What do you expect this program will print?
package main import "fmt" func main() { x := 100 for i := 0; i < 5; i++ { x := i fmt.Println(x) } fmt.Println(x) }
There are several scopes in a Go program; block scope, function scope, file scope, package scope, and universe scope. Each scope encompasses the previous. What you are seeing is called shadowing.
var x = 100 func main() { var x = 200 fmt.Println(x) }
Most developers are comfortable with a function scoped variable shadowing a package scoped variable.
func f() { var x = 99 if x > 90 { x := 60 fmt.Println(x) } }
But a block scoped variable shadowing a function scoped variable may be surprising.
The justification for a declaration in one scope shadowing another is consistency, prohibiting just block scoped declarations from shadowing another scope, would be inconsistent.