Parameters, multiple returns, variadic, closures, and defer.
defer
defer schedules a function call to run when the enclosing function returns
(by return, by reaching the end, or by panicking). It's Go's answer to
"try/finally" and to RAII.
The basics
go playground
Loading...
The output is:
running main
1 — first deferred
2 — middle
3 — cleanup
Deferred calls run in LIFO order (last in, first out) — like a stack. This means
you can pair Open / Close in the order you intuitively want:
f, err := os.Open("data.txt")
if err != nil { return err }
defer f.Close() // happens last, after all other work
// ... use f ...
Arguments are evaluated immediately
The arguments of a deferred call are evaluated right away, even though the call itself doesn't run until later.
go playground
Loading...
This prints:
now: 99
deferred sees: 1
To defer something that uses the current value at return time, wrap it in a closure:
defer func() { fmt.Println("now:", n) }()
Real-world uses
// 1. unlock a mutex
mu.Lock()
defer mu.Unlock()
// 2. close a network connection
conn, _ := net.Dial("tcp", addr)
defer conn.Close()
// 3. recover from a panic
defer func() {
if r := recover(); r != nil {
log.Println("recovered:", r)
}
}()
We cover recover properly in chapter 15.
In what order do deferred calls run?