What do f(), g(), and h() return?
Question 482HardGo 1.22 to 1.25
func f() (r int) {
defer func() { r *= 2 }()
return 3
}
func g() int {
r := 3
defer func() { r *= 2 }()
return r
}
func h() (r int) {
defer func() { r *= 2 }()
r = 1
return r + 10
}
f() returns 6, g() returns 3, and h() returns 22.
return X is not atomic. It first assigns X to the result parameter, then runs the deferred functions, then returns. With a named result, a deferred closure can read and change that result after the assignment. In f, r becomes 3 and then 6. In h, r becomes 11 and then 22.
In g the result is unnamed. The closure changes the local r, but the return value was already copied into an unnamed result slot, so the caller gets 3.
This is the mechanism behind the common idiom defer func() { if err != nil { err = fmt.Errorf("op: %w", err) } }() and behind turning a recovered panic into a returned error. The interviewer wants the three-step explanation.
More on Tricky Output & Code-Review Puzzles
- Q480What does this print, and what is the bug in the second function?
- Q481When are deferred call arguments evaluated? What prints?
- Q483What does this append puzzle print?
- Q484What does the caller see after calling modify?
- Q485Code review: what is wrong with returning a small sub-slice of a large buffer, and what does s[low:high:max] fix?
- Q486Array vs slice in range: what prints?