patterngoModeratepending
Go defer patterns and resource cleanup
Viewed 0 times
defercleanupcloserecoverpanicLIFO
Problem
Need to ensure resources are properly cleaned up in Go, even when functions return early or panic.
Solution
Defer patterns for reliable cleanup:
// Basic: close file
func readFile(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close() // Runs when function returns
return io.ReadAll(f)
}
// Defer runs LIFO (stack order)
func example() {
defer fmt.Println("first") // Runs third
defer fmt.Println("second") // Runs second
defer fmt.Println("third") // Runs first
}
// Capture error from deferred close
func writeFile(path string, data []byte) (err error) {
f, err := os.Create(path)
if err != nil {
return err
}
defer func() {
closeErr := f.Close()
if err == nil {
err = closeErr // Only override if no prior error
}
}()
_, err = f.Write(data)
return err
}
// Mutex unlock
func (s *SafeMap) Get(key string) string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.data[key]
}
// Recover from panic
func safeExecute(fn func()) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v", r)
}
}()
fn()
return nil
}
// Timer pattern
func timeIt(name string) func() {
start := time.Now()
return func() {
fmt.Printf("%s took %v\n", name, time.Since(start))
}
}
// Usage: defer timeIt("process")()Why
Defer guarantees cleanup even when functions panic or return early from multiple points. It's Go's equivalent of try-finally.
Gotchas
- Defer arguments are evaluated immediately, not when deferred function runs
- Defer in a loop creates one deferred call per iteration - can cause resource exhaustion
Context
Go code managing resources that need cleanup
Revisions (0)
No revisions yet.