Go

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

All 39 Language Fundamentals & Types questions