Go 中 panic 是运行时崩溃机制,需用 defer + recover 捕获:defer 必须在 panic 前注册,recover 仅在 defer 函数内有效,可停止 panic 传播并恢复执行,但不修复错误状态。

在 Go 中,panic 不是传统意义上的“异常”,而是一种运行时错误导致的程序崩溃机制。它会立即中断当前函数执行,并向上逐层传播,直到被 recover 捕获,或最终终止整个程序。要安全地处理 panic,必须配合 defer 和 recover 使用——且仅在 defer 调用的函数中调用 recover 才有效。
defer 必须在 panic 发生前注册
defer 语句会在函数返回前(包括因 panic 而提前返回)按后进先出顺序执行。因此,想捕获 panic,defer 的调用必须出现在 panic 可能发生的位置之前:
- 不能写在 if panic 条件成立之后,否则不会执行
- 推荐放在函数开头,确保始终注册
- 例如:
defer func() { if r := recover(); r != nil { log.Println("Recovered:", r) } }()
recover 只在 defer 函数中有效
recover 是一个内建函数,只能在 defer 延迟执行的函数内部调用才起作用。如果直接在普通逻辑中调用,它总是返回 nil:
- ✅ 正确:在
defer func() { recover() }()中调用 - ❌ 错误:在
if err != nil { recover() }中调用(此时 panic 已传播出去或尚未发生) - recover 返回 interface{} 类型,通常需类型断言或直接打印
recover 后程序可继续执行,但需谨慎设计流程
成功调用 recover 会停止 panic 的传播,并恢复 goroutine 的正常执行。但这不等于“错误已修复”:
立即学习“go语言免费学习笔记(深入)”;
- panic 的原始上下文(如栈信息、变量状态)已丢失,无法回滚操作
- 应避免在关键路径(如数据库事务、文件写入中途)依赖 recover 恢复业务逻辑
- 更合适的做法是:记录 panic、清理资源(如关闭文件/连接)、返回错误或优雅退出
实际使用中的常见模式
典型的安全包装方式是用匿名函数包裹可能 panic 的代码块:
- 封装为工具函数,如
SafeRun(func()) error,统一 recover 并返回错误 - HTTP handler 中常用:
defer func() { if r := recover(); r != nil { http.Error(w, "Internal Error", http.StatusInternalServerError) } }() - 注意:recover 无法捕获由
os.Exit或协程外的系统级崩溃(如 SIGKILL)引发的终止










