Skip to main content
eLearner.app
Module 3 · Lesson 5 of 515/50 in the course~12 min
Module lessons (5/5)

`defer`: guaranteed cleanup

defer postpones the execution of a call until the enclosing function returns. It runs even if the function exits via panic. Multiple defers in the same function execute in LIFO order (Last-In, First-Out).

It's the idiomatic mechanism for resource cleanup: closing files, unlocking mutexes, releasing connections, restoring state.

Syntax and canonical use case

Go
f, err := os.Open(path)
if err != nil {
    return err
}
defer f.Close()   // chiamata SEMPRE all'uscita della funzione

// ... usa f liberamente ...
return nil

Typical: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(), recover().

Arguments evaluated immediately, execution postponed

When you write defer foo(x), x is evaluated at the time of the defer, not at execution time:

Go
x := 10
defer fmt.Println(x)   // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"

LIFO order

Defers stack up and execute starting with the most recent:

Go
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1

This is consistent with resource semantics: the last opened is the first to be closed.

defer + recover: handling panic

defer is the only way to intercept a panic:

Go
func safe() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("recuperato:", r)
        }
    }()
    panic("boom")
}

Pitfall: defer in a loop

Putting defer f.Close() in a loop accumulates defers until the end of the function, not of each iteration. In a long loop you open many files and only close them when the function exits: risk of file descriptor leak.

Go
// MALE: defer accumulati
for _, path := range paths {
    f, _ := os.Open(path)
    defer f.Close()   // chiude TUTTI alla fine della funzione esterna
    // ...
}

// MEGLIO: estrai in una funzione
for _, path := range paths {
    elabora(path)   // ogni chiamata ha il proprio scope di defer
}

Try it

Exercise#go.m3.l5.e1
Attempts: 0Loading…

Print 'inizio', then defer the print of 'fine' with defer, then print 'mezzo'. The output must be: inizio / mezzo / fine.

Loading editor…
Show hint

The defer runs when main() is about to return.

Solution available after 3 attempts

Exercise#go.m3.l5.e2
Attempts: 0Loading…

Write three consecutive defers that print 1, 2 and 3 in that order in the code. The output will be 3 / 2 / 1 (LIFO).

Loading editor…
Show hint

Three defers in sequence; remember they execute in reverse order.

Solution available after 3 attempts

Quiz#go.m3.l5.e3
Ready

What does this print? (note: defer arguments are evaluated immediately)

Go
x := 10
defer fmt.Println(x)
x = 99
Answer options

Recap

  • defer call() postpones execution until the function returns.
  • Multiple defers = LIFO order.
  • Arguments evaluated immediately, execution postponed.
  • Used for deterministic cleanup: files, mutexes, connections.
  • defer + recover() intercepts a panic (rare, at boundaries).
  • Never defer inside a long loop: it accumulates until the outer function returns.