recover 只在 defer 函数内部直接调用才有效,必须先注册 defer 再 panic;无法捕获子 goroutine 的 panic;recover 后不可继续业务逻辑,仅用于记录日志和安全退出。

recover 只在 defer 函数内部直接调用才有效,其他任何写法都返回 nil —— 这不是 bug,是 Go 的确定性设计。
recover 必须写在 defer 匿名函数里,且 defer 要在 panic 前注册
常见错误是把 recover() 放在普通代码块、if 分支或 panic() 后面,这些位置根本不会执行,或执行时 panic 已结束。
- ❌ 错误:
func f() { panic("x"); r := recover() }——recover()永远执行不到 - ❌ 错误:
func f() { panic("x"); defer func() { r := recover() }() }——defer在 panic 之后注册,已失效 - ✅ 正确:
func f() { defer func() { if r := recover(); r != nil { log.Print(r) } }(); panic("x") }——defer先注册,recover()在其内部直接调用
recover 无法捕获子 goroutine 的 panic
每个 goroutine 有独立的 panic/recover 作用域。主线程写了 defer + recover,对 go func() { panic("x") }() 完全无效 —— 子 goroutine 会静默崩溃,主 goroutine 继续运行,你收不到任何通知。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- HTTP worker 池中,每个 worker 必须自带
defer func() { recover() }(),不能指望中间件统一兜底 - 封装
safeGo(f)启动协程时,f内部仍需自己加defer,否则没用 - 没有“全局 recover”机制,跨 goroutine 捕获是语言层面不支持的
recover 后不能继续业务逻辑,状态大概率已损坏
recover() 成功只意味着 goroutine 不退出,它不回滚任何副作用,也不修复变量、锁、channel 或文件句柄状态。
立即学习“go语言免费学习笔记(深入)”;
- panic 前可能已部分更新结构体字段、解引用空指针、向已关闭 channel 写入 —— 这些破坏不可逆
- 不要在
recover分支里调用 DB 写入、HTTP 请求、或依赖局部变量的函数 - 合理做法:记录 panic 栈和 request ID → 返回 500 或 fallback 响应 → 显式
return或清理后退出当前任务
最易被忽略的一点:recover 不是 error 替代品,也不是事务回滚工具;它只提供一次“软着陆”机会,用错比不用更危险。

















