这三个关键字处理延迟执行和异常情况。defer 调度清理代码,panic 触发运行时崩溃(用于真正的异常情况),recover 可以捕捉 panic 以防止程序崩溃。
defer — 在函数返回时调度执行一个调用
go
{
f, err := os.Open()
err != { err }
f.Close()
}
defer 调度一个函数调用在其所在函数返回时执行——无论以何种方式返回(正常返回、错误或 panic)。它是确保清理的惯用方式:关闭文件、解锁互斥锁、关闭连接——放在资源获取的紧邻位置,这样你就不会忘记。
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
// prints: 3, 2, 1 — last deferred, first executed (stack order)
func mustPositive(n int) {
if n < 0 {
panic("negative not allowed") // stops normal execution, unwinds the stack
}
}
// panic runs deferred functions as it unwinds, then crashes the program (with a stack trace)
panic 停止正常流程并展开调用栈(沿途运行延迟函数),最终导致程序崩溃。它用于 程序员错误 / 无法恢复的条件(越界访问、nil 解引用、不可能的状态)——不用于普通错误(这些应该用返回的 error 值来处理)。
func safeProcess() {
defer func() {
if r := recover(); r != nil { // recover() returns the panic value
fmt.Println("recovered from:", r) // handle it; program continues
}
}()
panic("something broke") // this panic is caught by the recover above
}
// safeProcess returns normally instead of crashing
recover 恢复对 panicking goroutine 的控制——但 仅在延迟函数内工作。使用场景很少,比如防止单个请求处理器使整个服务器崩溃。
Normal/expected failures (file missing, bad input, validation) → return an error value
panic/recover → reserve for TRULY exceptional cases (bugs, unrecoverable states)
and boundaries (e.g. a server recovering so one bad request doesn't kill the process)
defer 是一个基本的、惯用的 Go 特性,用于 保证清理——将资源释放放在资源获取的紧邻位置,并确保它在每个返回路径上都运行(包括 panic),这样比手动清理更加可靠地防止了文件、锁和连接泄漏。
理解其 LIFO 顺序也很重要。panic/recover 提供了类似异常的机制,但 关键原则 是 Go 将它们保留用于真正异常的、无法恢复的情况——普通错误应该始终作为返回值处理和检查。
将 panic/recover 误用为通用异常处理是不符合惯例的,这是来自基于异常的语言的开发者常见的错误。
了解何时使用 defer(总是用于清理)、error 返回(普通失败)和 panic/recover(稀有、异常或在边界处)是编写正确、符合 Go 惯例的代码的基础,也是常见的面试主题。