Essential Go Defer  Suggest an edit

Defer in depth

defer statements marks a function to be executed at a later time.

Defer statement is an ordinary function call prefixed by the keyword defer.

defer someFunction()

A deferred function is executed once the function that contains the defer statement returns. Actual call to the deferred function occurs when the enclosing function: - executes a return statement - falls off the end - panics

Example:

func logExit(name string) {
	fmt.Printf("Function %s returned\n", name)
}

func main() {
	fmt.Println("First main statement")
	defer logExit("main") // position of defer statement here does not matter
	fmt.Println("Last main statement")
}
First main statement
Last main statement
Function main returned

If a function has multiple deferred statements, they form a stack. The last defer is the first one to execute after the enclosing function returns, followed by subsequent calls to preceding defers in order (below example returns by causing a panic):

func logNum(i int) {
	fmt.Printf("Num %d\n", i)
}

func main() {
	defer logNum(1)
	fmt.Println("First main statement")
	defer logNum(2)
	defer logNum(3)
	panic("panic occurred")

	fmt.Println("Last main statement") // not printed

	// not deferred since execution flow never reaches this line
	defer logNum(3)
}
First main statement
Num 3
Num 2
Num 1
panic: panic occurred

goroutine 1 [running]:
main.main()
	/private/var/folders/2k/p2_4052s70vd5_cfdm0k0l740000gn/T/src485930671/main.go:16 +0xf0
exit status 2

Deferred functions have their arguments evaluated at the time defer executes:

func logNum(i int) {
	fmt.Printf("Num %d\n", i)
}

func main() {
	i := 1
	defer logNum(i) // deferred function call: logNum(1)
	fmt.Println("First main statement")
	i++
	defer logNum(i)     // deferred function call: logNum(2)
	defer logNum(i * i) // deferred function call: logNum(4)
}
First main statement
Num 4
Num 2
Num 1

If a function has named return values, a deferred anonymous function within that function can access and update the returned value even after the function has returned:

func plusOne(i int) (result int) {
	// anonymous function must be called by adding ()
	defer func() { result++ }()

	// i is returned as result, which is updated by deferred function above
	// after execution of below return
	return i
}

func main() {
	fmt.Println(plusOne(1)) // 2
}
2
Defer/
Defer in depth
Defer gotchas
  ↑ ↓ to navigate     ↵ to select     Esc to close