Defer in depth
suggest changedefer
statements marks a function to be executed at the end of current function.
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 defer
s 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(4)
}
First main statement
Num 3
Num 2
Num 1
panic: panic occurred
goroutine 1 [running]:
main.main()
/tmp/src508180251/main.go:17 +0x152
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