recover必须写在defer中才有效,直接调用或置于panic后无defer包裹则无效;panic非error替代品,仅适用于不可恢复的致命错误;子goroutine需独立recover;recover后不可继续业务逻辑,应清理资源并退出。

recover 必须写在 defer 里,否则完全无效
这是最常踩的坑:把 recover() 直接写在函数体中,或者放在 panic() 后面但不在 defer 内部——此时它永远返回 nil,起不到任何作用。
-
recover()只有在defer注册的函数执行时调用才可能捕获 panic;它不是“全局监听器” - 必须确保
defer语句在panic()发生前已执行(即 defer 要写在易错逻辑之前) - 错误写法:
func bad() {<br> panic("oops")<br> r := recover() // ❌ 永远不会执行到这行<br>} - 正确写法:
func good() {<br> defer func() {<br> if r := recover(); r != nil {<br> log.Printf("caught: %v", r)<br> }<br> }()<br> panic("oops") // ✅ defer 已注册,能捕获<br>}
panic 不是 error 替代品,别用它处理业务错误
把除零、参数校验失败、记录未找到这类可预期问题包装成 panic,会破坏调用链的可控性,也让错误难以测试和传播。
- ✅ 正确方式:
divide(a, b float64) (float64, error)—— 显式返回error,调用方可用if err != nil安全处理 - ❌ 错误方式:
panic("division by zero")—— 强制上层加recover,掩盖真实语义,且无法被errors.Is或errors.As检查 - 真正适合
panic的场景极少:程序启动时配置加载失败、关键依赖(如数据库连接池)初始化崩溃、类型断言失败且本不该发生(v.(MyType)中v明确应为MyType)
子 goroutine 的 panic 无法被外层 recover 捕获
每个 goroutine 有独立的 panic/recover 作用域。主 goroutine 的 defer + recover 对子 goroutine 里的 panic 完全无感。
Delphi 7应用编程150例 CHM全书内容下载,全书主要通过150个实例,全面、深入地介绍了用Delphi 7开发应用程序的常用方法和技巧,主要讲解了用Delphi 7进行界面效果处理、图像处理、图形与多媒体开发、系统功能控制、文件处理、网络与数据库开发,以及组件应用等内容。这些实例简单实用、典型性强、功能突出,很多实例使用的技术稍加扩展可以解决同类问题。使用本书最好的方法是通过学习掌握实例中的技术或技巧,然后使用这些技术尝试实现更复杂的功能并应用到更多方面。本书主要针对具有一定Delphi基础知识
- 子 goroutine panic 后只会终止自己,不会影响主线程,但也**不会自动触发任何 recover**
- 若需防护,必须在子 goroutine 内部显式加
defer:go func() {<br> defer func() {<br> if r := recover(); r != nil {<br> log.Printf("worker panic: %v", r)<br> }<br> }()<br> doWork()<br>}() - 常见陷阱:用
safeRun(f)包裹一个启动 goroutine 的函数,却忘了 goroutine 内部仍需自己的 recover
recover 后不能“继续执行”,状态可能已损坏
recover() 的作用只是停止 panic 传播、让 goroutine 恢复调度,但它**不会回到 panic 那一行继续跑**,更不会自动修复已被破坏的内存或资源状态。
立即学习“go语言免费学习笔记(深入)”;
- panic 常伴随严重副作用:空指针解引用可能已改写随机内存、channel 关闭后写入可能触发竞态、事务中途 panic 可能留下未提交/未回滚状态
- 安全做法是:recover → 记录完整堆栈 → 清理当前函数级资源(如关闭临时文件、释放锁)→ 返回错误或提前退出,**不继续走后续业务逻辑**
- 尤其避免在 HTTP handler 中 recover 后还尝试写响应体或更新数据库——除非你 100% 确认 panic 发生点之前所有状态都干净且可重入
真正难的不是写对 defer 和 recover 的语法,而是判断“这里该 panic 吗”“这里该 recover 吗”“recover 之后我还能信什么”。Go 把选择权交给你,而不是替你决定——这点一旦想错,debug 成本远高于多写几行 if err != nil。









