recover 只在 panic 发生中且同 goroutine 的 defer 函数内直接调用时才有效;若跨 goroutine、被封装或不在 panic 调用栈中,recover 返回 nil。

defer 中 recover 为什么经常失效
recover 只在 panic 正在发生、且当前 goroutine 尚未退出时有效;如果 defer 函数本身不是直接在 panic 的调用栈中(比如被封装成闭包、跨 goroutine 调用,或放在了错误的函数层级),recover() 会返回 nil,看似“没捕获到”。最常见的情况是:把 defer 写在了被调用函数里,而 panic 发生在它的调用者中——这时 defer 根本没机会执行。
必须满足的三个条件才能让 recover 生效
缺一不可:
-
defer语句必须出现在和panic相同的 goroutine 中 -
defer的函数必须在panic之后、函数返回之前执行(即它得是 panic 路径上尚未 return 的 defer) -
recover()必须在defer函数内部**直接调用**,不能包在另一个函数里(例如不能写成func() { recover() }())
正确写法示例与典型错误对比
✅ 正确(recover 在 defer 函数体第一层):
func risky() {
defer func() {
if r := recover(); r != nil {
log.Printf("caught: %v", r)
}
}()
panic("something went wrong")
}
❌ 错误(recover 被包在额外函数中,失去上下文):
func risky() {
defer func() {
// 这个匿名函数只是触发了另一个函数,recover 不在 defer 的直接调用栈中
go func() {
recover() // 永远返回 nil,且运行在新 goroutine
}()
}()
panic("...") // 主 goroutine panic,但上面的 recover 在别的 goroutine 执行
}
⚠️ 注意:recover() 只能拦截当前 goroutine 的 panic,无法跨 goroutine 传递或捕获。
recover 后程序还能继续运行吗
可以,但仅限于当前函数的 defer 阶段结束后正常返回;panic 被 recover 后,控制权交还给 defer 所在函数,该函数可以继续执行后续语句(只要没再 panic)。不过要注意:
- recover 不会“撤销”已经发生的 panic,它只是终止 panic 的传播
- 被 panic 中断的代码(panic 之后、defer 之前的语句)不会执行
- 如果 defer 函数里 recover 后又 panic,依然会向外传播
- 不要依赖 recover 来做常规错误处理——它是兜底机制,不是 error 替代品
真正容易被忽略的是:recover 必须紧挨着 defer 定义,且不能有任何间接调用层级。一旦加了中间函数、协程、方法调用或提前 return,就大概率失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











