Defer pitfalls

suggest change

When using defer keep the following in mind: deferred functions are called at the end of a function.

Deferred statements have a function scope, not a block scope.

In other words: deferred calls are executed when exiting a function not when executing block created with if or for statements.

func main() {
	fmt.Print("Before if\n")
	if true {
		defer fmt.Print("inside if\n")

	fmt.Print("Ater if\n")
Before if
Ater if
inside if

You might expect that deferred statement to be executed when we exit if branch but it’s executed as the last thing in a function.

Using outside variables in defer functions

func main() {
	for i := 0; i < 2; i++ {
		defer func() {
			fmt.Printf("%d\n", i)

A common mistake is to think that this code will print 0 and 1. Those are the values of i when we see defer.

However, defer creates a closure which only captures variable i by a reference. It doesn't capture the value of the variable.

It should be become clear when we look at what code executes:

var i int
for i = 0; i < 2; i++ {
	// create closure that references i by reference

fmt.Printf("%d\n", i) // from created by defer in second loop iteration (remember: reverse order)
fmt.Printf("%d\n", i) // from closure created by defer in first loop iteration

Now it’s clear that when we call deferred fmt.Printf, i is 2.

We can fix this by forcing a capture of the variable:

func main() {
	for i := 0; i < 2; i++ {
		defer func(i2 int) {
			fmt.Printf("%d\n", i2)

A closure might be slightly more expensive as it requires allocating an object to collect all the variables captured by the closure.

Feedback about page:

Optional: your email if you want me to get back to you:

Table Of Contents