SyntaxStudy
Sign Up
Go Defer, Panic, and Recover
Go Beginner 1 min read

Defer, Panic, and Recover

The `defer` statement schedules a function call to be executed just before the surrounding function returns, regardless of whether the return is normal or due to a panic. Deferred calls are pushed onto a stack and execute in last-in, first-out order. This makes `defer` ideal for resource cleanup such as closing files, releasing locks, or completing transactions. A `panic` is a runtime event that stops normal execution of the current goroutine. It propagates up the call stack, running deferred functions along the way, until either the goroutine's stack is exhausted (crashing the program) or a `recover` call intercepts the panic. Panics should be reserved for truly unrecoverable situations such as programming errors or invariant violations. The `recover` built-in function can only be called inside a deferred function. When called during a panic, it stops the panic propagation and returns the value that was passed to `panic`. This pattern is commonly used in library code to convert panics into errors, providing a cleaner API to callers who should not need to deal with panics.
Example
package main

import (
    "fmt"
    "os"
)

// safeDiv recovers from a panic and returns an error instead.
func safeDiv(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    result = a / b // panics if b == 0
    return
}

// openFile shows defer for cleanup
func openFile(name string) error {
    f, err := os.Open(name)
    if err != nil {
        return err
    }
    defer f.Close() // guaranteed to run

    // ... process file ...
    fmt.Println("opened:", f.Name())
    return nil
}

// deferOrder shows LIFO execution
func deferOrder() {
    for i := 0; i < 3; i++ {
        defer fmt.Printf("deferred %d\n", i)
    }
    fmt.Println("after loop")
}

func main() {
    res, err := safeDiv(10, 2)
    fmt.Println("10/2 =", res, err)

    res, err = safeDiv(10, 0)
    fmt.Println("10/0 =", res, err)

    _ = openFile("nonexistent.txt")

    deferOrder()
    // prints: after loop, deferred 2, deferred 1, deferred 0
}