go语言之defer,panic,recover实例分析

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值