recover只能捕获同goroutine中defer函数内的panic,不能处理error;必须用defer func(){if r:=recover();r!=nil{}}()形式,跨goroutine、非defer调用或顺序错误均无效。

recover 不能恢复错误,只能捕获 panic;它不是 error 拦截器,也不是 try-catch 替代品。 把 recover 当作“全局异常处理器”或“错误兜底开关”,是 Go 新手最常导致服务更不稳定的误用方式。
recover 必须和 defer 组合使用,且仅在同 goroutine 中生效
recover() 单独调用永远返回 nil,它只在 panic 发生后、且处于同一 goroutine 的 defer 函数中执行时才起作用。
- ✅ 正确写法:
defer func() { recover() }()—— 匿名函数被 defer 注册,panic 触发后该函数执行,此时 recover 才能拿到 panic 值 - ❌ 错误写法:
defer recover()—— 这会在 defer 注册时立刻执行 recover,此时还没 panic,返回nil,且语法上 Go 编译器会直接报错 - ❌ 跨 goroutine 失效:子 goroutine 中
panic("boom"),主 goroutine 的 defer 里调用recover()完全捕不到,程序照样崩溃 - ⚠️ 注意顺序:
defer必须在panic之前注册,否则 panic 一发生函数就退出,defer 根本没机会注册
recover 返回值是 interface{},不做类型判断直接断言会二次 panic
panic 可以传任意类型:panic("string")、panic(errors.New("x"))、panic(&MyError{}),但 recover() 返回的是 interface{},强行转成具体类型前必须检查。
- ❌ 危险操作:
err.(error).Error()—— 如果 panic 传的是字符串,这行代码自己就会 panic - ✅ 安全做法:先判空再分支,例如
switch r := recover().(type) { case error: ... case string: ... default: fmt.Sprint(r) } - ? 提示:日志记录推荐统一用
fmt.Sprint(r),避免因类型不匹配中断恢复流程
recover 不是 error 处理机制,滥用会掩盖真正问题
Go 的 error 是值,用于可预期、可恢复的失败(如文件不存在、网络超时);panic 是控制流中断,表示程序已处于不可信状态(如 nil map 写入、空指针解引用)。
立即学习“go语言免费学习笔记(深入)”;
- ? 不该用 recover 拦截:
json.Unmarshal失败、os.Open返回 error、HTTP 请求返回 4xx/5xx —— 这些都该走if err != nil分支 - ✅ 合理使用场景:Web 服务器单个连接处理 goroutine 崩溃、第三方 Cgo 库意外触发运行时 panic、初始化阶段发现配置严重损坏无法继续
- ⚠️ 关键限制:recover 无法释放已泄露的资源(比如已分配未关闭的文件描述符、已加锁未解锁的 mutex),它只恢复执行流,不回滚状态
真正难的不是写对 recover,而是判断「这里到底该 panic 还是该 return error」——这个决策点一旦错位,后续所有 recover 都是在给坏设计打补丁。


















