recover仅在同goroutine的defer函数内调用才有效,用于捕获本协程内panic;对fatal错误、跨goroutine panic、非defer位置调用均无效,且recover后不可继续依赖损坏状态执行业务逻辑。

recover在子goroutine中完全捕获不到panic
主goroutine里写defer func() { recover() }(),对go func() { panic("x") }()里的panic毫无作用——recover()返回nil,程序照样崩溃或子goroutine静默退出。
- 每个goroutine有独立的panic/recover作用域,
recover只认自己这个协程栈里正在传播的panic - 子goroutine panic后不会通知父goroutine,也不会触发父goroutine的任何
defer - HTTP handler、定时任务、worker这类常起新goroutine的场景,必须在
go内部自己加defer+recover,不能指望外层兜底
recover调用不在defer函数体内就必然失效
recover()单独写在函数体里(不在defer匿名函数中),或者写成defer recover(),永远返回nil,Go编译器甚至会直接报错。
- 正确写法只能是:
defer func() { recover() }(),且该defer语句必须出现在panic()之前 -
defer recover()是语法错误:它会在注册时立刻执行recover(),此时还没panic,返回nil,且无法编译通过 - 常见误写:
panic("boom"); defer func() { recover() }()——panic一发生函数就退出,defer根本没机会注册
recover对runtime.fatal类错误完全无效
不是所有以panic:开头的输出都能被recover()截住。像fatal error: stack overflow、throw: out of memory、signal SIGKILL这类,recover()插不上手。
- 判断依据很直观:看错误输出有没有完整的goroutine stack trace。有trace的一般可recover;直接
fatal error:开头或进程无声退出的,recover无效 - 底层由
runtime.throw或runtime.fatal触发的终止,绕过panic机制,不走defer链 - 并发写map、严重内存泄漏、栈溢出等场景,recover只是摆设,得靠监控和压测提前暴露
recover成功后继续业务逻辑极易引发二次panic
recover()只让goroutine从panic状态“软着陆”,不修复已破坏的状态。紧接着调用依赖该状态的代码(比如继续写DB、发HTTP请求、访问刚越界的切片),大概率二次panic。
- panic可能发生在任意中间点:刚unlock了mutex、刚close了channel、结构体字段只赋了一半
- recover分支里只适合做清理(关闭文件、释放锁)、记录日志、返回fallback响应,然后
return或os.Exit(1) - 别把recover当成try-catch——它不是重试机制,更不是事务回滚,状态损坏就是损坏了
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











