Go 语言中的 `recover()` 函数详解
recover()
是 Go 语言中用于处理 panic 的内置函数,它允许程序管理发生 panic 的 goroutine 的行为。下面我将详细解释它的工作原理和使用方法。
基本概念
1. 函数签名
func recover() any
2. 核心功能
recover()
可以:
- 停止 panic 的传播
- 返回传递给
panic()
的值 - 恢复正常的程序执行
工作原理
1. 使用位置
recover()
必须在 defer 函数中直接调用才有效:
defer func() {if r := recover(); r != nil {// 处理 panic}
}()
2. 返回值
- 当 goroutine 正在 panic 且在 defer 函数中调用时:返回传递给
panic()
的值 - 其他情况(包括 panic 参数为 nil 的情况,Go 1.21 之前):返回 nil
使用示例
基本用法
func mayPanic() {panic("something went wrong")
}func main() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()mayPanic()fmt.Println("This will not be executed if panic occurs")
}
输出:Recovered from panic: something went wrong
实际应用场景
func safeDivide(a, b int) (result int, err error) {defer func() {if r := recover(); r != nil {err = fmt.Errorf("runtime error: %v", r)}}()return a / b, nil
}
重要特性
- 必须与 defer 配合使用:只有在 defer 函数中直接调用才有效
- 作用域限制:只能恢复同一个 goroutine 中的 panic
- Go 1.21 的变化:
- 之前版本:
panic(nil)
时recover()
返回 nil - Go 1.21+:
panic(nil)
会引发 runtime panic,recover()
返回*runtime.PanicNilError
- 之前版本:
注意事项
- 不要滥用 recover:应该只用于处理真正的意外情况,而不是替代常规错误处理
- 资源清理:即使 panic 被 recover,defer 函数仍然会执行
- 跨 goroutine:无法恢复其他 goroutine 的 panic
- 性能影响:panic/recover 比常规错误处理机制性能差
与 panic 的关系
recover()
和 panic()
是配套使用的:
func doSomething() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r)}}()if somethingWrong {panic("critical error")}
}
最佳实践
- 为关键代码段添加 recover
- 记录 recover 到的错误信息
- 尽量让程序在 recover 后能继续正常运行
- 避免在库函数中静默地 recover 而不返回错误