文章目录
panic和recover是Go语言中用于处理程序异常情况的机制,与传统的try-catch异常处理不同,Go更推荐使用error返回值来处理可预期的错误,而panic/recover主要用于处理不可恢复的错误或程序中的严重问题。
有些资料会讲这些处理称为自定义错误处理。
panic
基本概念
panic是Go语言的内置函数,用于(主动调用)引发运行时恐慌(类似其他语言的抛出异常),可终止当前 goroutine 的正常执行流程。当函数调用panic时:
1、当前函数的执行立即停止,Panic后的函数不再执行。
2、所有defer语句会按照后进先出的顺序执行(如果存在defer语句的话)。
3、程序会回溯调用栈,直到被recover捕获或程序崩溃。
4、如果直至主函数main仍未捕获panic,程序将打印错误信息、堆栈跟踪,并以非零状态码退出。
使用场景
func main() {
fmt.Println("程序开始")
panic("发生了严重错误") // 触发panic
fmt.Println("这行不会执行") // 不会执行
}
// 输出
程序开始
panic: 发生了严重错误
goroutine 1 [running]:
main.main()
/tmp/sandbox123456/main.go:7 +0x95
与error对比
特性 | panic | error |
---|---|---|
用途 | 不可恢复的严重错误 | 预期的、可处理的错误情况 |
传播方式 | 自动向上传播调用栈 | 需要通过返回值显式传递 |
处理方式 | 必须用recover捕获 | 通过if err != nil检查处理 |
适用场景 | 程序无法继续执行的严重问题 | 正常的错误处理流程 |
recover
基本概念
recover是Go语言的内置函数,用于捕获panic并恢复程序执行。recover只有在defer函数中调用才有效。
使用方法
func mayPanic() {
panic("出问题了!")
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("恢复panic:", r)
}
}()
mayPanic()
fmt.Println("这行会在recover后执行") // 不会执行
}
// 输出
恢复panic: 出问题了!
工作原理
1、recover只有在defer函数中调用才能捕获panic。
2、recover会返回panic传递的值。
3、如果当前goroutine没有发生panic,recover返回nil。
4、recover捕获panic后,程序会从recover调用点之后继续执行。
执行流程
1、panic触发时:
当前函数的执行立即停止,开始执行该goroutine的defer栈(后进先出)。
2、recover捕获:在defer函数中调用recover会捕获panic,recover返回panic传递的值,panic被处理后,程序控制流不会回到panic发生的位置。
3、程序继续执行的位置:recover后,程序会从当前函数(main)的defer之后继续执行,不会回到Painc调用后的位置。
总结
何时使用panic
1、不可恢复的错误:如数据库连接失败导致程序无法继续。
2、程序员的错误:如API被错误调用,传入非法参数。
3、启动时依赖不满足:如配置文件缺失或格式错误。
何时使用recover
1、防止程序崩溃:如HTTP服务器中单个请求处理失败不应导致整个服务崩溃。
2、资源清理:确保在panic发生时释放锁、关闭文件等。
3、日志记录:记录panic信息用于调试。
相关好文推荐(纯推荐,如有侵权,请告知)
基础文章:
Go 语言中的 Panic:处理不可恢复错误的紧急机制
进阶学习:
深入理解 Go 语言中的 Panic 机制