Defer
Use defer for cleanup at the point resources are acquired, but understand its execution cost and timing.
Canonical guidance
- call
deferimmediately after successful acquisition of a resource - use it for cleanup paths like
Close,Unlock, and cancellation - remember deferred calls run at function return in LIFO order
- avoid
deferin very hot loops when it is measurable and unnecessary
Use when
- file cleanup
- mutex unlocks
- context cancellation
- tracing and timing hooks
Avoid
- deferring cleanup before checking acquisition errors
- piling up defers inside large loops accidentally
- replacing normal control flow with defer cleverness
Preferred pattern
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
Anti-pattern
for _, name := range names {
f, _ := os.Open(name)
defer f.Close()
}
Explanation: This anti-pattern is common because defer is concise, but in loops it can keep files or locks alive far longer than intended.
Why
- defer keeps cleanup close to setup
- misuse in loops can retain resources longer than intended
Sources
- Defer, Panic, and Recover - Andrew Gerrand
- Effective Go - Go Team