golang中恐慌的恢复传播方式总是记不住,故此记载
func main() {
// 每个未恢复的恐慌与此协程调用栈中的一个尚未退出的函数相关联
go func() {
defer func() {
// 最终恢复的恐慌是恐慌2
fmt.Println(recover())
}()
// 该函数调用退出时恐慌2将蔓延替换恐慌0与外层函数相关联
defer func() {
// 新传播出来的恐慌2将蔓延替换恐慌1与外层函数相关联
defer panic(2)
// 调用完毕恐慌1将蔓延到外层与外层匿名函数相关联
func() {
panic(1)
}()
}()
// 与最外层函数相关联
panic(0)
}()
select {}
}
其他需要注意的是:
- panic只会触发当前goroutine的延迟调用函数
func main() {
defer func() {
fmt.Print(recover())
}()
defer func() {
defer fmt.Print(recover())
panic(1)
}()
defer recover()
panic(2)
}
上面函数输出21,defer recover()
未在函数中调用,无效。panic与主函数绑定,接着调用
defer func() {
defer fmt.Print(recover())
panic(1)
}()
由于defer fmt.Print(recover())
参数recover()
在入参时估值为2,panic(2)恢复,panic(1)蔓延到外层main
被第一个defer中的recover恢复
如果是下面的写法则输出12
func main() {
defer func() {
fmt.Print(recover())
}()
defer func() {
defer func() {
fmt.Print(recover())
}()
panic(1)
}()
defer recover()
panic(2)
}
因为函数内部在调用时进行估值,此时
defer func() {
defer func() {
fmt.Print(recover())
}()
panic(1)
}()
中的recover恢复的panic(1)