Day 8 — Control Flow & defer
Learning Objectives
- Understand
deferexecution order and why it's essential for resource cleanup - Use
switchwithout fallthrough for clean dispatch - Know when
forreplaceswhile,do-while, andloop
Key Concepts
// defer — runs when the surrounding function returns, LIFO order
// Arguments are evaluated when defer is called, not when it runs
func processRequest(conn net.Conn) {
defer conn.Close() // runs last: cleanup
defer logRequest(time.Now()) // evaluated NOW, logged later
// ... process ...
}
// Multiple defers — LIFO (last in, first out)
func example() {
defer fmt.Println("3") // runs third
defer fmt.Println("2") // runs second
defer fmt.Println("1") // runs first
}
// Output: 1, 2, 3
// switch — no fallthrough by default (unlike C/Java)
switch r.Method {
case "GET", "HEAD":
handleRead(w, r)
case "POST", "PUT", "PATCH":
handleWrite(w, r)
case "DELETE":
handleDelete(w, r)
default:
http.Error(w, "method not allowed", 405)
}
// for — the only loop in Go
for i := 0; i < 10; i++ { } // C-style
for condition { } // while-style
for { } // infinite loop
for i, v := range slice { } // range
for k, v := range m { } // map range
Exercise: Request Lifecycle Simulator
package main
import (
"fmt"
"sync/atomic"
"time"
)
var activeRequests atomic.Int64
func simulateRequest(id int) {
activeRequests.Add(1)
// Defers register in order, execute in reverse — critical for connection cleanup
defer func() {
activeRequests.Add(-1)
fmt.Printf("[%d] counter decremented, active=%d\n", id, activeRequests.Load())
}()
defer func() { fmt.Printf("[%d] 3. log request complete\n", id) }()
defer func() { fmt.Printf("[%d] 2. release connection to pool\n", id) }()
defer func() { fmt.Printf("[%d] 1. close response body\n", id) }()
fmt.Printf("[%d] processing...\n", id)
time.Sleep(10 * time.Millisecond)
fmt.Printf("[%d] done processing\n", id)
}
func main() {
for i := 1; i <= 3; i++ {
simulateRequest(i)
fmt.Println("---")
}
fmt.Printf("final active requests: %d\n", activeRequests.Load())
}
Expected output shows cleanup in reverse order: close body → release conn → log → decrement
Real-World Context
Leaked connections cause CLOSE_WAIT sockets (you'll debug these in Day 52). Every net.Conn, http.Response.Body, and os.File must be defer-closed. The order matters: release the connection after you close the body.