Use `defer` to schedule a function call for when its surrounding function returns. The call runs after a return statement, at the end of the function, or during panic unwinding. Put cleanup immediately after successfully acquiring a resource so later work cannot leave it open. section 4.3.3 section 1.2.2
Close an HTTP response body
After `http.Get` succeeds, write `defer resp.Body.Close()` before reading with `io.ReadAll(resp.Body)`. The body is closed when `main` returns, including if later work panics. section 1.2.2
A deferred closure can also inspect a panic: `defer func() { if err := recover(); err != nil { fmt.Println(err) } }()`. The trailing `()` marks the function call to defer; it does not execute the body immediately. `recover` retrieves the panic value and stops further stack unwinding. section 4.3.4
Two practical boundaries matter:
- A closure can read a variable declared before the `defer` statement, including a value assigned later. A variable declared afterward is not in scope there. section 4.3.4
- `log.Fatal*` calls `os.Exit`, so deferred calls do not run. `log.Panicln` permits panic unwinding and deferred cleanup. section 7.2.1
Listing 7.7 Network log client
package main
import (
"log"
"net"
)
func main() {
conn, err := net.Dial("tcp", "localhost:1902") #1
if err != nil {
panic("Failed to connect to localhost:1902")
}
defer conn.Close() #2
f := log.Ldate | log.Lshortfile #3
logger := log.New(conn, "example ", f) #4
logger.Println("This is a regular message.")
logger.Panicln("This is a panic.") #5
}
The network log client defers `conn.Close()` after connecting, then logs through that connection and triggers a panic with `logger.Panicln`. Closing during unwinding helps flush buffered log messages. section 7.2.1


