Go语言中的异常处理
这是我参与更文挑战的第8天,活动详情查看: 更文挑战
不积跬步,无以至千里;不积小流,无以成江海。骐骥一跃,不能十步,驽马十驾,功在不舍。锲而舍之,朽木不折;锲而不舍,金石可镂。
在上篇分析singleflight的相关资料中,看到有文章说“doCall方法巧妙的使用两个defer来区分调用函数异常与系统异常”。今天查找资料,学习一下Go的异常处理机制,目前的大概印象,只知道一个关键字panic
。
异常与错误
在Go语言中,错误被认为是一种可以预期的结果;而异常则是一种非预期的结果,发生异常可能表示程序中存在BUG或发生了其它不可控的问题。
Go 中主要通过 error 和 panic 分别表示错误和异常[2]
例如,从一个map
查询一个结果时,可以通过额外的布尔值判断是否成功,属于一种预期的结果。
1 | if v, ok := m["key"]; ok { |
错误
Go中的错误类型:error
1 | type error interface { |
内置的 error 接口使得开发人员可以为错误添加任何所需的信息,error 可以是实现 Error() 方法的任何类型,具体例子可参考[2]。
Go中errors包提供了几个常用的函数,包括errors.New, errors.Is, errors.As, errors.Unwrap
,以及使用fmt.Errorf
。
erros.Is
判断两个error
是否相等,error.As
判断error
是否为特定类型。
使用实例
函数通常可在最后一个返回值中返回错误信息,一个简单的应用实例:
1 | package main |
异常
defer,panic recover搭配可以处理异常。
defer
当程序出现异常,如数组访问越界这类“意料之外”的错误时,它能够导致程序运行崩溃,此时就需要开发人员捕获异常并恢复程序的正常运行流程。捕获异常不是最终的目的。如果异常不可预测,直接输出异常信息是最好的处理方式[1]。
defer
是Go提供的一种延迟执行机制,每次执行 defer,都会将对应的函数压入栈中。在函数返回或者 panic 异常结束时,Go 会依次从栈中取出延迟函数执行。
panic
panic
用于主动抛出程序执行的异常,会终止其后将要执行的代码,并依次逆序执行 panic 所在函数可能存在的 defer 函数列表。
recover
recover
关键字主要用于捕获异常,将程序状态从严重的错误中恢复到正常状态。 必须在 defer 函数中才能生效。
下面是一个defer+panic+recover的代码样例,可以看到,在手动panic后,执行了defer中的输出,并且,a
的值为0,所以如果函数中有panic语句,name函数应该需要返回一个error
。
1 | package main |
代码输出结果:
1 | 0 |
一个处理极端
超级健壮的代码,每个函数开始的地方都添加如下代码:
1 | func myfunc() { |
当然,不要总这么做~~~
[1] 错误和异常
[2] 没有 try-catch,该如何处理 Go 错误异常
[3] Go语言中defer的一些坑