Lesson 12 / 26
defer, panic and recover
Cleanup and last-resort recovery.
LIFO cleanup, recover only in deferred functions
defer schedules a call to run when the surrounding function returns, in last-in-first-out order, which is ideal for cleanup (defer f.Close(), defer mu.Unlock()). A panic (from a bug such as an out-of-range index, or an explicit panic) unwinds the stack running deferred calls; recover() inside a deferred function stops the panic and returns its value. Use panic only for programmer errors and impossible states, not for ordinary failures, and recover at boundaries such as an HTTP handler so one bad request does not crash the server.
Deferred calls and recovering a panic, run
I ran this with Go 1.27.1 (go run . in a module named demo, standard library only). risky(1) returns normally; risky(10) panics with an index out of range, which the deferred recover converts into a returned message. The three deferred prints run last, in reverse order.
package main
import "fmt"
func risky(n int) (result string) {
defer func() {
if r := recover(); r != nil { // turn a panic into a normal return
result = fmt.Sprint("recovered: ", r)
}
}()
items := []int{1, 2, 3}
return fmt.Sprint("item: ", items[n])
}
func main() {
for i := 1; i <= 3; i++ {
defer fmt.Println("deferred", i) // runs in LIFO order when main returns
}
fmt.Println(risky(1))
fmt.Println(risky(10))
fmt.Println("main body done")
}
Output:
item: 2 recovered: runtime error: index out of range [10] with length 3 main body done deferred 3 deferred 2 deferred 1
Defer cleanup right after acquiring
Write defer f.Close() immediately after a successful Open, so every return path releases the resource.
Quick check: In what order do deferred calls run?
- First in, first out
- Last in, first out
- Randomly
- Alphabetically
Answer
Last in, first out — Like a stack.