Golang的panic和recover
panic
关键字panic的作用是制造一次宕机,宕机就代表程序运行终止,但是已经“生效”的延迟函数仍会执行(即已经压入栈的defer延迟函数,panic之前的)。
为什么要制造宕机呢?是因为宕机不容易遇到?还是因为程序有错就是直接报错,都没有执行,哪来的宕机?
Go程序设计语言中这样提到:如果碰到“不可能发生的”的状况,宕机是最好的处理方式。这个“不可能发生的”状况很难理解,不过可以这样想:一个机器人的能源供应,可能依靠太阳能,可能依靠电能,但是如果靠吃饭解决,那么这肯定就不可思议了,这时候就应该触发一次宕机。
关于panic,下面是一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main import "fmt" func main(){ defer func (){ fmt.Println( "aaaaaa" ) }() fmt.Println( "bbbbbb" ) fmt.Println( "cccccc" ) panic( "hahahaha" ) fmt.Println( "ddddd" ) defer func (){ fmt.Println( "eeeeeeee" ) }() } |
首先顺序执行,会先将第一个defer延迟函数“入栈”(这里称为入栈是为了便于理解),然后输出“bbbbbbb",”cccccccc”,此时使用panic来触发一次宕机,panic接受一个任意类型的参数,会将该字符串输出,用作提示信息,之后的代码不再执行,所以后面的dddddd不会输出,而且第二个defer延迟函数也不会“入栈”,因为panic之后的代码不会继续执行,程序现在只会运行已经“入栈”的defer延迟函数,输出aaaaaa,在最后,会输出此次触发宕机的一些信息,所以执行结果如下:
1
2
3
4
5
6
7
8
9
|
bbbbbb cccccc aaaaaa panic: hahahaha goroutine 1 [running]: main.main() /Users/root/Desktop/test. go :9 +0xf1 exit status 2 |
为什么不执行panic后面的defer,其实这个很好理解,比如,有两次读文件操作,那么每一次读文件之后都是用defer关闭文件,如果第一次读文件就引发了panic异常,而第二次读文件操作还没开始,也就是说还没有打开文件,那么调用第二个defer来关闭第二个文件,有意义吗?应该是只关闭第一个打开的文件,对吧?也就是调用第一个defer。
recover
recover从英文的意思上就知道是恢复,那么这个恢复是恢复什么呢?是恢复运行状态,继续运行?还是恢复到宕机之前?
其实,recover在英文中指的是受伤的愈合,防止伤口进一步感染。伤是愈合了,但是伤了始终是伤了,愈合只不过是事后处理而已。所以golang中的recover也只是发生宕机之后的后事处理。
所以这里的recover只是用来接收panic触发的宕机,如果panic触发宕机,传给panic的任意类型的参数,recover会接收到这个参数,recover获取到值之后才知道发生了宕机;相反,如果程序中的recover没有获取到值,则代表没有发生宕机,那么recover的值就为nil,通过这个可以来进一步处理后事。
前面已经提到panic的时候,已经说了,一旦发生宕机,其后的代码是不会执行的,但是会调用位于panic代码所在的哪一行之前的defer延迟函数,所以说这个特性就决定recover应该用在defer函数中,否则一旦发生宕机,除了defer延迟函数中的语句还能执行外,其他的语句都是不能执行的。
如果触发宕机,panic的错误信息会显示,如果有recover时,则信息会被recover截获,于是错误信息就不会显示,转而进行下一步操作。
下面是一个简单的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package main import "fmt" func main() { defer func () { if info := recover(); info != nil { fmt.Println( "触发了宕机" , info) } else { fmt.Println( "程序正常退出" ) } }() fmt.Println( "bbbbbb" ) fmt.Println( "cccccc" ) panic( "fatal error" ) fmt.Println( "ddddd" ) defer func () { fmt.Println( "eeeeeeee" ) }() } |
运行结果如下:
1
2
3
|
bbbbbb cccccc 触发了宕机 fatal error |
转自 https://www.cnblogs.com/-beyond/p/8394691.html