go语言之 panic, recover ——如何在go语言中优雅的处理错误

概念

在go语言中,panic和recover是何方神圣?

详细参见:https://golang.org/pkg/builtin/

func panic(v interface{})

The panic built-in function stops normal execution of the current goroutine. When a function F calls panic, normal execution of F stops immediately. Any functions whose execution was deferred by F are run in the usual way, and then F returns to its caller. To the caller G, the invocation of F then behaves like a call to panic, terminating G's execution and running any deferred functions. This continues until all functions in the executing goroutine have stopped, in reverse order. At that point, the program is terminated and the error condition is reported, including the value of the argument to pa. This termination sequence is called panicking and can be controlled by the built-in function recover.

func recover() interface{}

The recover built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function (but not any function called by it) stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil, recover returns nil. Thus the return value from recover reports whether the goroutine is panicking.

panic:
1、内建函数
2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行
3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行
4、直到goroutine整个退出,并报告错误

recover:
1、内建函数
2、用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为
3、一般的调用建议
    a). 在defer函数中,通过recever来终止一个gojroutine的panicking过程,从而恢复正常代码的执行
    b). 可以获取通过panic传递的error


代码示例


调用函数定义:





被调用函数定义:




调用代码:




从运行结果可以看出:
1、当遇到panic,panic之后的语句是不会执行的 “I 'm children, I 'm eating”
2、被调用函数 “Test_TheCallee_F_toverify_panic_and_recover_func” 中的所有defer定义都会按照逆序执行,才会返回到调用函数。不管被调用函数中任意一个defer中是否使用recover处理了panic
3、调用函数 “Test_Caller_G” 在被调用函数返回后,是否会继续向下执行代码,取决于被调用函数是否处理了panic还是继续执行panic
4、例子中,由于被调用函数 ”Test_TheCallee_F_toverify_panic_and_recover_func“ 的 某个defer “deferOfTheCallee”的定义中处理了panic(只是答应message到屏幕),并没有继续执行panic来触发panicking,所以调用函数执行完后,仍然可以继续向下处理代码


通过构建panic的时候,传入非error类型,来继续触发panic,我们来看看输出结果:

修改代码(panic只传递一个字符串,非error类型):


修改后的执行结果:


最终的结论:
1、panic在程序中出现,如果不使用recover在defer中处理,goroutine最终回退出。退出的整个流程详细参见panic的官方说明文档介绍
2、recover建议只写在defer中,可以提供一个通用的defer,在很多需要处理错误的方法内部,最终都会执行这个defer
3、在这个通用defer的逻辑内部,通过recover来处理是否继续将错误panic,还是只是处理错误。具体的做法可以参见如下文章:

a). https://www.zhihu.com/question/27158146
b). https://github.com/reusee/codes/blob/master/err/err.go
c). https://github.com/reusee/socks5hs/blob/master/socks5hs.go#L37


关于如何在代码中避免到处使用 
if err != nil {
    return err
}
可以参见go的官方推荐方法:
https://blog.golang.org/errors-are-values

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值