When are deferred call arguments evaluated? What prints?
Question 481MediumGo 1.22 to 1.25
func main() {
x := 1
defer fmt.Println("a", x)
defer func() { fmt.Println("b", x) }()
x = 2
}
Output:
b 2
a 1
The function value and arguments of a deferred call are evaluated at the defer statement. Only the call itself waits. fmt.Println("a", x) captured the value 1. The closure has no arguments and reads the variable x when it runs, so it sees 2. The order is reversed because defers run LIFO.
This also applies to receivers. In defer t.Method() or defer mu.Unlock(), the receiver (and, for a value receiver, a copy of it) is fixed at defer time. A common real bug is defer log.Printf("took %v", time.Since(start)), which measures almost zero because time.Since runs right away. Use defer func() { log.Printf("took %v", time.Since(start)) }() instead.
More on Tricky Output & Code-Review Puzzles
- Q479What do these two loops print when the body changes the loop variable?
- Q480What does this print, and what is the bug in the second function?
- Q482What do f(), g(), and h() return?
- 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?