recover必须在defer中调用才有效,仅能在panic发生且goroutine未退出时捕获本协程panic,不可跨goroutine,非错误处理替代品,应限于真正不可恢复的意外,recover后状态不可信,不可续跑逻辑。

recover 必须在 defer 中调用,否则无效
Go 没有传统意义上的“异常捕获”,recover 不是 try-catch,它只在 panic 正在发生、且当前 goroutine 尚未退出时起作用。一旦 panic 开始传播并离开当前函数,再调用 recover 就返回 nil,什么也捞不到。
常见错误是把 recover 写在普通逻辑里,比如:
func bad() {
panic("boom")
recover() // 永远不执行,或执行了也返回 nil
}
正确姿势只有一种:必须配合 defer,且 defer 的函数体里要直接调用 recover():
-
defer注册的函数会在函数 return 前执行,此时 panic 还没终止 goroutine,recover才有机会生效 - 如果
defer本身在 panic 后才注册(比如写在 panic 之后),那它根本不会运行 - 多个
defer会按后进先出顺序执行,recover应该放在最靠近 panic 发生点的外层defer里,避免被更早的defer消耗掉 panic 状态
recover 只能捕获本 goroutine 的 panic
Go 的 recover 是 goroutine 局部的,无法跨协程捕获。主 goroutine panic 了,子 goroutine 里的 recover 完全无感;反过来也一样。
立即学习“go语言免费学习笔记(深入)”;
典型误用场景:
- 在
go func() { panic(...) }()里试图用外部recover捕获 —— 不可能 - 启动一个 goroutine 做关键任务,却不加自己的
defer/recover—— panic 会直接 crash 整个程序 - 想靠全局 handler 统一兜底?Go 没这机制;每个可能 panic 的 goroutine 都得自己配
defer func() { recover() }()
示例:
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("goroutine panicked: %v", r)
}
}()
panic("in goroutine")
}()
recover 不是错误处理替代品,别滥用
Go 鼓励显式错误返回(error),panic/recover 应仅用于真正不可恢复的意外,比如空指针解引用、切片越界、类型断言失败等。把它当 try-catch 来处理业务错误,会破坏控制流、掩盖真实问题、增加调试难度。
容易踩的坑:
- 对
json.Unmarshal、os.Open这类明确返回error的操作套recover—— 完全没必要,且掩盖了本该检查的 error - 在 HTTP handler 里 blanket
defer recover吞掉所有 panic,却不记录日志或返回 500 —— 用户看到空白页,你却不知道哪崩了 - recover 后继续执行后续逻辑,但状态可能已损坏(比如 panic 发生在中间件里,context 已失效)
合理做法:只在顶层入口(如 http.HandlerFunc 最外层)做一次 recover,记录 panic 并返回 500,其余地方靠 if err != nil 处理可预期错误。
recover 后的程序状态不可信,别假定还能继续安全运行
Go 的 panic 是栈展开过程,recover 只是中止展开、让函数正常 return,但它不回滚任何已发生的副作用:文件句柄可能已泄露、数据库事务没 rollback、channel 发送可能卡住、全局变量可能已被改写。
这意味着:
- recover 后不要试图“续跑”原逻辑,尤其别重试或继续处理请求数据
- 如果 panic 发生在初始化阶段(
init函数),整个包加载失败,后续调用都 panic,recover也没用 - 某些底层 panic(如 runtime.throw)根本不能被 recover,比如
fatal error: concurrent map writes—— 这种直接终止进程,recover完全无效
语言学习稳定性保障的关键,其实是写少一点 panic,多一点 error 判断,把 recover 当成最后的保险丝,而不是日常开关。

















