recover的过程 #
可以通过 recover 函数来实现捕捉 panic 并恢复程序正常执行秩序。
Panicking过程,在触发 panic 的 bar 函数中,对 panic 进行捕捉并恢复,我们直接来看恢复后,整个程序的执行情况是什么样的。
func bar() {
defer func() {
if e := recover(); e != nil {
fmt.Println("recover the panic:", e)
}
}()
println("call bar")
panic("panic occurs in bar")
zoo()
println("exit bar")
}
我们在一个 defer 匿名函数中调用 recover 函数对 panic 进行了捕捉。 recover 是 Go 内置的专门用于恢复 panic 的函数,它必须被放在一个 defer 函数中才能生效。如果 recover 捕捉到 panic,它就会返回以 panic 的具体内容为错误上下文信息的错误值。如果没有 panic 发生,那么 recover 将返回 nil。而且,如果 panic 被 recover 捕捉到,panic 引发的 panicking 过程就会停止。
我们执行更新后的程序,得到如下结果:
call main
call foo
call bar
recover the panic: panic occurs in bar
exit foo
exit main
我们可以看到 main 函数终于得以“善终”。那这个过程中究竟发生了什么呢?
在更新后的代码中,当 bar 函数调用 panic 函数触发异常后,bar 函数的执行就会被中断。但这一次,在代码执行流回到 bar 函数调用者之前,bar 函数中的、在 panic 之前就已经被设置成功的 derfer 函数就会被执行。这个匿名函数会调用 recover 把刚刚触发的 panic 恢复,这样,panic 还没等沿着函数栈向上走,就被消除了。
所以,这个时候,从 foo 函数的视角来看,bar 函数与正常返回没有什么差别。 foo 函数依旧继续向下执行,直至 main 函数成功返回。这样,这个程序的 panic“危机”就解除了。