Errors · 3 MIN READ

defer runs last in, first out

Release what you acquired, in the right order, on every path.

A deferred call runs when the function returns, whichever return it was, and deferred calls run in reverse order. That is what makes acquire-then-defer-release safe against every early return an error check introduces.

The argument to a deferred call is evaluated immediately; only the call is postponed. This surprises people exactly once.

SEE THE IDEA

Cleanup belongs next to successful acquisition

  1. 01

    Acquire

    go
    resource, err := open()

    Handle a failure first

  2. 02

    Register

    go
    defer resource.Close()

    Cleanup is now tied to this function

  3. 03

    Exit

    go
    return result

    Deferred cleanup runs before the caller continues

All ordinary return paths pass through the registered cleanup.

In practice

Register a close only after acquisition succeeds. Defer also runs during panic unwinding in the same goroutine. If closing can report a relevant failure, decide how that error participates in the result rather than discarding it by habit.

Watch out

Calling os.Exit does not run deferred functions. A defer in a long loop also waits until the surrounding function exits.

Official reference ↗

Read and predict

go
package main

import "fmt"

func main() {
	for i := 1; i <= 3; i++ {
		defer fmt.Print(i, " ")
	}
	fmt.Print("end ")
}

In what order do the numbers print?

Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.