Defer, Panic, Recover
Defer, Panic, and Recover in Go
defer A deferred function call runs after the surrounding function returns, regardless of how (normal return, panic, etc.). Deferred calls are pushed onto a stack and execute in LIFO (last-in, first-out) order.
Common use: resource cleanup paired with acquisition:
f, err := os.Open("file.txt")
if err != nil { log.Fatal(err) }
defer f.Close() // always runs when the function exitspanic
panic stops normal execution, runs deferred functions, then propagates up the call stack. Use it for unrecoverable programming errors (not for normal error handling).
recover
recover stops a panic in progress and returns the panic value. It must be called inside a deferred function to have any effect:
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()Key points:
- Prefer returning
errorvalues over panicking for expected failures. - Use panic/recover at library boundaries to convert panics to errors.
- Deferred function arguments are evaluated when the defer statement executes, not when the deferred function runs.
Code Examples
package main
import "fmt"
func countDown() {
fmt.Println("Start")
for i := 1; i <= 3; i++ {
defer fmt.Println("deferred:", i)
}
fmt.Println("End")
}
func main() {
countDown()
}Deferred calls execute in LIFO order after the function returns. Arguments (i) are captured at defer time, not execution time.
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered panic: %v", r)
}
}()
result = a / b // panics if b == 0
return
}
func main() {
r1, err := safeDivide(10, 2)
fmt.Println(r1, err)
r2, err := safeDivide(10, 0)
fmt.Println(r2, err)
}recover() inside a deferred function catches the panic and lets you return an error instead of crashing.
Quick Quiz
1. In what order do multiple deferred calls execute?
2. Where must `recover()` be called to catch a panic?
Was this lesson helpful?