recover只能在defer函数中且panic尚未传播出当前goroutine时生效;必须在defer匿名函数内直接调用,仅捕获本goroutine panic,返回interface{}需类型断言,不可替代错误处理。

recover 不能捕获所有 panic,只能在 defer 函数中且 panic 尚未传播出当前 goroutine 时生效。
recover 必须配合 defer 使用才有效
单独调用 recover() 没有意义——它只在 defer 函数执行期间、且当前 goroutine 正处于 panic 状态时返回非 nil 值。一旦 panic 已经向上冒泡到函数返回点,recover() 就会返回 nil。
- 错误写法:
recover()放在普通语句位置(如 if 分支里),永远返回nil - 正确写法:必须包裹在
defer的匿名函数中,且该函数在 panic 发生后仍有机会执行 - 典型结构:
defer func() { if r := recover(); r != nil { // 处理 panic } }()
recover 只能捕获当前 goroutine 的 panic
Go 的 panic 是 goroutine 局部的,recover() 对其他 goroutine 中发生的 panic 完全无感。主 goroutine panic 后程序直接退出,子 goroutine panic 不影响主线程,但也不会被主线程的 recover() 捕获。
- 常见误判:在 main 函数里写 defer+recover,以为能兜住所有子 goroutine 错误 → 实际无效
- 子 goroutine 需要自己做
defer+recover(),否则 panic 会导致该 goroutine 终止,可能引发资源泄漏或状态不一致 - 如果想统一处理,需在每个 goroutine 入口手动加 recover 逻辑,或封装成工具函数如
safeGo(func(){...})
recover 返回值类型是 interface{},需要类型断言才能获取真实错误
recover() 返回的是 interface{},不是 error。虽然大多数 panic 是由 panic(err) 触发的,但也可以是任意值(比如 panic("oops") 或 panic(42))。
- 直接用
fmt.Println(r)能打印,但无法调用Error()方法 - 安全做法是先判断类型:
if r, ok := recover().(error); ok { log.Printf("panic as error: %v", r) } else { log.Printf("panic as unknown value: %v", r) } - 忽略类型断言直接转
error可能导致 panic(比如r.(error).Error()在 r 是 string 时 panic)
recover 不是 try-catch,不能用于控制流程或替代错误检查
Go 设计哲学是“显式错误优先”,panic/recover 仅用于真正异常、不可恢复的场景(如空指针解引用、切片越界),而非业务错误(如文件不存在、网络超时)。
- 滥用 recover 会让错误处理逻辑分散、难以测试,还掩盖真正的 bug
- HTTP handler 中用 recover 捕获 panic 防止服务崩溃是合理场景;但在解析 JSON 时用 panic 替代
json.Unmarshal返回的 error 就属于误用 - recover 后程序继续运行,但栈已展开、局部变量可能处于不一致状态,不要假设 panic 后的代码还能安全执行原逻辑
最常被忽略的一点:recover 之后,程序不会自动“回滚”任何已完成的操作。比如 defer 中 recover 了 panic,但之前已写入数据库的数据、已发送的 HTTP 请求、已关闭的文件句柄,都不会自动撤销或重置。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











