Defer
Cleaning Up After Yourself
The defer keyword schedules a function call to run when the surrounding function returns. It is Go's way of ensuring cleanup happens no matter how the function exits.
func main() {
fmt.Println("start")
defer fmt.Println("deferred")
fmt.Println("end")
}
// Output:
// start
// end
// deferred
The deferred call runs after the function body completes but before it returns to the caller.
On the bridge of the Enterprise, the captain might say: "Engage! But first, make sure someone closes the shuttlebay doors." That is
deferin a nutshell.
LIFO Order
When you defer multiple calls, they execute in last-in, first-out order --- like a stack:
func main() {
defer fmt.Println("first")
defer fmt.Println("second")
defer fmt.Println("third")
}
// Output:
// third
// second
// first
Common Pattern: Open Then Defer Close
The most common use of defer is pairing resource acquisition with cleanup on the very next line:
f, err := os.Open("data.txt")
if err != nil {
return err
}
defer f.Close()
// work with f...
This makes it impossible to forget to close the file, regardless of how many return paths the function has.
Arguments Are Evaluated Immediately
The arguments to a deferred call are evaluated when the defer statement executes, not when the deferred function runs:
x := 10
defer fmt.Println(x) // captures 10
x = 20
// prints 10, not 20
Defer in Loops
Be careful with defer inside loops. Deferred calls accumulate and only run when the function returns, not when the loop iteration ends:
for _, name := range files {
f, _ := os.Open(name)
defer f.Close() // these all pile up!
}
If you need per-iteration cleanup, extract the body into a separate function so each deferred call runs promptly.
Your Task
Write a function countdown(n int) that uses defer inside a loop to print numbers in reverse order, followed by "Go!".
For example, countdown(3) should print:
3
2
1
Go!
Hint: defer each number inside the loop. Since deferred calls execute in LIFO order, deferring 1, 2, 3 will print 3, 2, 1. Think about where "Go!" needs to appear relative to the numbers, and remember that all deferred calls execute in LIFO order --- so if you defer "Go!" before the loop, it will be at the bottom of the stack and print last.