Go

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

All 38 Tricky Output & Code-Review Puzzles questions