前言
go语言追求简洁,所以go语言中没有try...catch语句。因为go语言的作者认为将异常和控制语句混在一起,很容易让这个程序变得混乱,异常也很容易被滥用。
所以在go语言中,为了防止异常被滥用。我们常常使用函数的返回值来返回错误,而不是用异常来代替错误。
如果在一些场景下确实需要处理异常,就可以使用panic和recover。panic用来抛出异常,recover用来恢复异常。
panic
panic触发流程:
- 如果函数F中书写并触发了panic语句,会终止其后要执行的代码。在panic所在函数F内如果存在要执行的defer函数列表,则按照defer书写顺序的逆序执行;
- 如果函数G调用函数F,则函数F panic后返回调用者函数G。函数G中,调用函数F语句之后的语句都不会执行。假如函数G中也有要执行的defer函数列表,则按照defer书写顺序的逆序子还行;
- 退出整个goroutine,并报告错误。
func main() {
defer fmt.Println("main---1---")
defer fmt.Println("main---2---")
fmt.Println("main---3---")
mytest(1)
defer fmt.Println("main---4---")
fmt.Println("main---5---")
}
func mytest(num int) {
defer fmt.Println("mytest---1---")
defer fmt.Println("mytest---2---")
fmt.Println("mytest---3---")
if num == 1 {
panic("出现异常,抛出panic")
}
defer fmt.Println("mytest---4---")
fmt.Println("mytest---5---")
}
代码执行流程:
从main函数进入 --> 遇到main函数中的2条defer语句 --> 打印"main---3---" --> 进入mytest函数
--> 遇到mytest函数中2条defer语句 --> 打印"mytest---3---" --> if语句为true触发panic --> 逆序执行mytest函数中的panic前的2条defer语句 --> 返回外部函数(main函数) --> 逆序执行main函数中的mytest函数前的2条defer语句 --> 抛出异常
由于panic抛出异常,可以看到mytest函数panic语句后面的语句都不被执行;返回外部函数后,mytest函数后的语句也都不被执行。
recover
- recover的作用是捕获panic,从而恢复正常代码执行;
- recover必须配合defer使用;
- recover没有传入参数,但是有返回值,返回值就是panic传递的值
recover示例
defer func() {
if msg := recover(); msg != nil {
fmt.Println("panic信息:", msg, "---recover恢复---")
}
}()
panic示例中的示例,如果在mytest中加入recover将panic恢复后,执行效果和顺序是如何的呢?
func main() {
defer fmt.Println("main---1---")
defer fmt.Println("main---2---")
fmt.Println("main---3---")
mytest(1)
defer fmt.Println("main---4---")
fmt.Println("main---5---")
}
func mytest(num int) {
defer func() {
if msg := recover(); msg != nil {
fmt.Println("panic信息:", msg, "---recover恢复---")
}
}()
defer fmt.Println("mytest---1---")
defer fmt.Println("mytest---2---")
fmt.Println("mytest---3---")
if num == 1 {
panic("出现异常,抛出panic")
}
defer fmt.Println("mytest---4---")
fmt.Println("mytest---5---")
}
代码执行流程:
从main函数进入 --> 遇到main函数中的2条defer语句 --> 打印"main---3---" --> 进入mytest函数
--> 遇到mytest函数中3条defer语句 --> 打印"mytest---3---" --> if语句为true触发panic --> 逆序执行mytest函数中的panic前的3条defer语句 --> 执行到第三条defer时,recover恢复恐慌并输出信息 --> 返回外部函数(main函数) --> 遇到mytest函数后的1条defer语句 --> 打印"mytest---5---" --> 逆序执行main函数中的3条defer语句
由于recover恢复恐慌,所以程序就不会因为panic而退出执行,所以mytest返回外部函数后,外部函数还能够正常执行下去。