Shadowing is when a variable in an inner scope hides ("shadows") a variable with the same name from an outer scope. In Go, this is possible due to the peculiarities of the short variable declaration :=, especially within blocks (if, for, switch, etc.).
x := 5 if true { x := 10 // This x is a new variable, only valid in this if fmt.Println(x) // 10 } fmt.Println(x) // 5, not 10
Sometimes this can be useful, but it often leads to errors if you forget that the redeclared variable is not the same as the outer variable.
Question: "What will the following code print?"
x := 7 if true { x, y := 1, 2 fmt.Println(x, y) } fmt.Println(x)
Answer:
if, new variables x and y will be declared, they are only accessible within the if block.x is still the same outer variable, its value won't change.Output:
1 2
7
Story
Resource Leak Due to Shadowing err: A typical mistake is shadowing the error variable when working with files.
f, err := os.Open("file.txt") if err != nil { return err } if err := f.Close(); err != nil { return err } // this is a new variable err!
The := operator creates a new err variable only within the block, while the outer err variable remains unchanged. If error handling is expected in the outer variable, this leads to the loss of error information.
Story
Shadowing Structures — Invisible Bugs: Inside a nested block, a developer redefined a structure with the same name. As a result, part of the logic operated on the inner version, while another part operated on the outer version, leading to strange bugs and data loss in the billing service.
Story
Shadowing in Loops Breaks Counts:
In an automated application processing system, := was used instead of = to increase the counter, causing a new variable to be created and incremented inside the loop, while the outer counter remained unchanged. The system undercounted applications and skewed important statistics.