GO

Go Fundamentals

18 lessons

Progress0%
1. Introduction to Go
1What is Go?
2. Variables and Data Types
1Data Types in Go
3. Control Flow
If, For, and SwitchDefer, Panic, Recover
4. Functions
Function BasicsError Handling
5. Structs and Methods
StructsMethods and Interfaces
6. Concurrency
Goroutines and ChannelsSelect and Sync
7. Maps & Slices Advanced
Slices Deep DiveMaps Operations & Patterns
8. Interfaces Deep Dive
Interface Composition & anyCommon Interfaces & Patterns
9. Packages & Modules
Package SystemGo Modules & Workspace
10. Testing & Standard Library
Testing in GoStandard Library Essentials
All Tutorials
GoControl Flow
Lesson 4 of 18 min
Chapter 3 · Lesson 2

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:

go
f, err := os.Open("file.txt")
if err != nil { log.Fatal(err) }
defer f.Close() // always runs when the function exits

panic 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:

go
defer func() {
    if r := recover(); r != nil {
        fmt.Println("Recovered:", r)
    }
}()

Key points:

  • Prefer returning error values 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

defer stack ordergo
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.

panic and recovergo
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?

PreviousNext