go语言之defer,panic,recover实例分析
一.defer,panic,recover简述
1.defer简述
defer一般用在资源释放、关闭连接等操作,会在函数关闭前调用。在物理实现上是以链表结构实现的,在使用时依照FILO栈方式逆序执行。
结构体说明:
type _defer struct {
size int32 // 参数的大小
started bool // 是否执行过了
sp uintptr // sp at time of defer
pc uintptr
fn *funcval
_panic *_panic // defer中的panic
link *_defer // defer链表,函数执行流程中的defer,会通过 link这个 属性进行串联
}
2.panic简述
panic在物理实现上是以链表结构实现的,每一次的panic都会追加到链表头部,链表的节点插入是头部插入方式。
结构体说明:
type _panic struct {
argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
arg interface{} // argument to panic
link *_panic // link to earlier panic
recovered bool // whether this panic is over
aborted bool // the panic was aborted
}
1.argp:指向 defer 延迟调用的参数的指针,就是发生panic时会弹出defer栈,执行defer函数;
2.arg:panic 的原因,也就是调用 panic 时传入的参数;
3.link:指向上一个历史的调用的 _panic;
4.recovered:panic 是否已经被处理过,也就是是否被 recover;
5.aborted:panic 是否被中止;
3.recover
recover必须在defer延迟调用内部直接使用才有效,用来捕获panic,从而恢复异常,让程序继续下去。
二. 实例分析
func test() {
defer func() {
//10.捕获panic(2)
fmt.Println("defer-1-recover : ", recover())
}()
defer func() {
defer func() {
defer func() {
//9.捕获panic(1),使panic(2)成为当前最新的未处理的panic
fmt.Println("defer-2-recover : ", recover())
}()
//8.此处的panic会追加到panic(2)前面,但是后面存在一个正常的recover,会被捕获
panic(1)
}()
func(){
//6.无效的捕获,没在defer的延迟方法内使用
fmt.Println("defer-3-recover : ", recover())
//7.此处的panic会追加到panic(4)前面
panic(2)
}()
//此处无法执行到
panic(3)
}()
defer func(){
//5.此处的panic会终止掉panic(5)(aborted=true),因此后面无法确保panic(5)会被恢复,原因在于此处的panic没有被及时恢复的可能性,只能等后面的机会
panic(4)
}()
//1.defer在入栈时会计算函数参数的,此时没有panic触发,所以recover空,但是执行打印延后
//4.执行之前计算好的打印
defer fmt.Println("defer-4-recover : ",recover())
//3.无效调用recover,defer panic(XXX)也是无效的操作,虽然编译器不会报错,但实际是不会执行的
defer recover()
//2.触发panic(5)
panic(5)
}
打印结果:
defer-4-recover : <nil>
defer-3-recover : <nil>
defer-2-recover : 1
defer-1-recover : 2
说明:上面注释中的序号是代码执行顺序的说明。
三. 结束
这个实例只是想让更多的gopher爱好者能够深入了解一下go语言,希望在实践中有所帮助。同时这个case,自己使用了delve进行调试,其中也发现了一些自己一直没发现的东西,也让自己更加深入了对这方面知识的理解。
参考
1.https://cloud.tencent.com/developer/article/1457294
2.https://segmentfault.com/a/1190000020307676