When are the arguments to a deferred call evaluated? What does this print?
Question 14MediumGo 1.22 to 1.25
func main() {
x := 1
defer fmt.Println("deferred arg:", x)
defer func() { fmt.Println("closure:", x) }()
x = 2
fmt.Println("body:", x)
}
Output:
body: 2
closure: 2
deferred arg: 1
When the defer statement runs, Go evaluates the function value and its arguments right away and saves them. Only the call itself waits until the surrounding function returns. So fmt.Println keeps x == 1. The closure takes no arguments. It captures the variable x, not a copy, so it sees the final value 2. Deferred calls run in LIFO order, which is why the closure prints first.
This matters in timing code:
func work() {
start := time.Now()
defer log.Println("took", time.Since(start)) // WRONG: time.Since is evaluated now, ~0s
defer func() { log.Println("took", time.Since(start)) }() // correct
// ...
}
Also, defer trace("f")() calls trace immediately and defers only the function it returns. This is a common trick for enter/exit logging.
More on Language Fundamentals & Types
- Q12What happens when you range over invalid UTF-8, and what does
string(65)produce? - Q13What does converting between
stringand[]bytecost, and how do you build strings efficiently? - Q15In what order do deferred calls run, and what is wrong with using
deferinside a loop? - Q16How can a deferred function change a function's return value? What do
f()andg()return? - Q17What does this print? (defer with value vs pointer receivers)
- Q18What are the rules for
recover? Why doesn'tdefer recover()stop a panic?