解释一下Go recover的执行时机 ?
参考回答
在 Golang 中,recover 的执行时机是在 defer 函数中捕获到 panic 时 才会执行。如果没有发生 panic 或者 recover 不在 defer 中调用,它不会生效。
recover 的作用是捕获 panic,从而阻止程序崩溃,允许程序继续运行或进行清理操作。它的典型使用场景是异常处理。
详细讲解与拓展
1. panic 和 recover 的机制
panic:用来主动中断程序执行,类似于抛出异常。当发生panic时,当前函数会立刻停止执行,并将控制权传递到调用链上的defer语句。recover:用来捕获panic,可以恢复程序的正常执行。
注意:recover 只有在 defer 中调用时,才能捕获到当前的 panic。
2. 执行顺序和示例
当 panic 发生时,以下顺序执行:
1. 停止当前函数的执行。
2. 调用已经定义的 defer 语句。
3. 如果在某个 defer 中调用了 recover,并成功捕获 panic,程序会恢复执行,panic 不会继续传播。
4. 如果没有 recover,panic 会沿调用链向上传播,最终导致程序崩溃。
示例 1:捕获 panic
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
fmt.Println("Before panic")
panic("Something went wrong!")
fmt.Println("After panic") // 不会执行
}
输出:
Before panic
Recovered from panic: Something went wrong!
解释:
1. panic("Something went wrong!") 触发 panic。
2. 调用 defer 中的匿名函数。
3. recover 捕获了 panic,程序恢复正常。
3. recover 的使用场景
(1) 防止程序崩溃
– 在关键逻辑中使用 recover,确保即使出现异常也不会导致整个程序崩溃。
示例:
“`go
func safeDivide(a, b int) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
fmt.Println(a / b) // 如果 b == 0,会引发 panic
}
func main() {
safeDivide(10, 0) // 捕获 panic
fmt.Println("Program continues running")
}
“`
输出:
“`
Recovered from panic: runtime error: integer divide by zero
Program continues running
“`
(2) 用于服务稳定性
– 在 Web 服务中,recover 可以避免因单个请求引发的异常导致整个服务崩溃。
示例:
“`go
func handler() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in handler:", r)
}
}()
panic("Handler panic!")
}
func main() {
handler()
fmt.Println("Server keeps running")
}
“`
4. recover 的注意事项
- 必须在
defer中调用:
如果直接调用recover()而不在defer中,是无法捕获panic的。func main() { fmt.Println(recover()) // 输出:<nil> } - 无法捕获 goroutine 中的
panic:
如果panic发生在独立的 goroutine 中,而没有在该 goroutine 内使用recover,则panic会导致该 goroutine 崩溃。func main() { go func() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in goroutine:", r) } }() panic("Goroutine panic!") }() // 主 goroutine 不会受到影响 fmt.Println("Main goroutine continues") } - 恢复之后的程序行为:
当recover捕获panic后,程序会从panic发生点最近的defer处继续执行。
总结
-
执行时机:
recover必须在defer中调用,并且只有发生了panic时才会生效。- 发生
panic后,函数停止执行,defer的代码块会被调用,recover捕获异常后可以恢复程序执行。
- 使用场景:
- 用于异常处理,防止程序崩溃。
- 在 Web 服务、任务调度中使用
recover提高系统稳定性。
- 注意事项:
- 无法捕获 goroutine 外的
panic。 - 如果不在
defer中调用,recover不会生效。
- 无法捕获 goroutine 外的
理解 panic 和 recover 的执行时机和原理,有助于更好地编写高健壮性的代码。