Spot the bug: why is err nil after the if block?
Question 494MediumGo 1.22 to 1.25
func parse(s string) (int, error) {
var n int
var err error
if s != "" {
n, err := strconv.Atoi(s) // := declares NEW n and err
if err != nil {
log.Println("inner:", err)
}
_ = n
}
return n, err // always (0, nil)
}
:= inside the if block declares new variables n and err that shadow the outer ones. The outer values are never set, so parse("abc") returns (0, nil) and the error is lost. Fix: use plain assignment, n, err = strconv.Atoi(s).
Related compile-time trap with named results:
func load() (err error) {
if true {
_, err := os.Open("x")
if err != nil {
return // compile error: result parameter err not in scope at return
}
}
return
}
Also be aware of the redeclaration rule. a, err := f() in the same scope reuses err as long as at least one new variable is on the left. In a nested scope it always creates a new variable. Tools: the shadow analyzer (go vet -vettool=$(which shadow)) and govet's shadow check in golangci-lint.
More on Tricky Output & Code-Review Puzzles
- Q492What happens if you add or delete map entries while ranging over the map?
- Q493Why won't m["a"].count++ compile, and what happens with a nil map?
- Q495Find the two WaitGroup bugs.
- Q496Why does this loop spin at 100% CPU after one channel closes?
- Q497What does this select print, and where does the break go?
- Q498What does each channel operation do on nil, open, and closed channels?