panic 和 recover
引发panic有两种情况,一种是程序主动调用panic函数,另一种是程序产生运行时错误,由运行时检测并抛出。
发生panic后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执·行函数的defer语句,然后逐层打印函数调用堆栈,直到被recover捕获或运行到最外层函数而退出。
任意类型的变量都可以传递给panic
panic不但可以在函数正常流程中抛出,在defer逻辑里也可以再次调用panic或抛出panic。defer里面的panic能够被后续执行的defer捕获。
recover()只有在defer后面的函数体内被直接调用才能捕获panic终止异常
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("first recover", r)
}
}()
defer func() {
if r := recover(); r != nil {
fmt.Println("second recover", r)
}
}()
if r := recover(); r != nil {
fmt.Println(" recover in main", r)
}
panic("panic in main")
fmt.Println()
}
/*输出
second recover panic in main
*/
func tmpFunc() {
panic("panic in tmpFunc")
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recover in main")
}
}()
tmpFunc()
fmt.Println()
}
/*输出
recover in main
*/
连续多个panic的场景只能出现在延迟调用里面,只有最后一次 panic 能被捕获
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("first recover", r)
}
}()
defer func() {
panic("panic in second defer")
if r := recover(); r != nil {
fmt.Println("second recover", r)
}
}()
if r := recover(); r != nil {
fmt.Println(" recover in main", r)
}
panic("panic in main")
fmt.Println()
}
/* 输出
first recover panic in second defer
*/