随着使用golang越来越频繁,发现golang有一个地方非常不方便,就是在错误处理方面。先来看看golang中通常的错误处理方法:

通常的error处理

​​package​​         ​​main​​       





​​import​​ ​​ (​​


​​"errors"​​


​​"fmt"​​


​​)​​





​​func​​ ​​ a() (err error) {​​


​​err = errors.New(​​ ​​"错误"​​ ​​)​​


​​return​​


​​}​​





​​func​​ ​​ main() {​​


​​err := a()​​


​​if​​ ​​err != nil {​​


​​fmt.Println(err)​​


​​}​​


​​}​​


函数在返回的时候增加error类型的返回值,如果有错误则赋值给err,在调用函数处对err进行判断,如果不为nil则处理错误。这种方式在嵌套的层少的时候还好办,要是嵌套的层多了那就要一级一级的返回err,显然会很麻烦。如下面的代码:

​​package​​         ​​main​​       





​​import​​ ​​ (​​


​​"errors"​​


​​"fmt"​​


​​)​​





​​func​​ ​​ a() (err error) {​​


​​err = b()​​


​​if​​ ​​err != nil {​​


​​return​​


​​}​​


​​err = c()​​


​​if​​ ​​err != nil {​​


​​return​​


​​}​​


​​err = errors.New(​​ ​​"a内错误"​​ ​​)​​


​​return​​


​​}​​





​​func​​ ​​ b() (err error) {​​


​​err = errors.New(​​ ​​"b内错误"​​ ​​)​​


​​return​​


​​}​​





​​func​​ ​​ c() (err error) {​​


​​err = errors.New(​​ ​​"c内错误"​​ ​​)​​


​​return​​


​​}​​





​​func​​ ​​ main() {​​


​​err := a()​​


​​if​​ ​​err != nil {​​


​​fmt.Println(err)​​


​​}​​


​​}​​


a函数内调用了b和c函数,调用后都要进行err != nil的判断,如果再来个d方法,e方法,那岂不是非常麻烦。在实际开发的时候,这种多层嵌套也经常存在,比如用户注册功能就要判断很多东西:表单验证是否OK;用户是否已经存在;数据插入是否OK等等。

用panic的尝试

于是我就想有没什么办法更加方便,至少不用调用每个函数都判断下err!=nil,这样就可以省掉三行代码。了解到golang中的panic方法可以直接中断流程,感觉到沿着这个应该能找到解决方法。了解了下panic的详细使用,其实也很简单,就是panic一下,如果需要捕获这个panic的错误,就在外围的方法事先声明recover方法。看下代码:

​​package​​         ​​main​​       





​​import​​ ​​ (​​


​​"log"​​


​​)​​





​​func​​ ​​ main() {​​


​​defer​​ ​​func​​ ​​() {​​


​​if​​ ​​r := recover(); r != nil {​​


​​log.Printf(​​ ​​"Runtime error caught: %v"​​ ​​, r)​​


​​}​​


​​}()​​





​​a()​​


​​}​​





​​func​​ ​​ a() {​​


​​panic(​​ ​​"a内错误"​​ ​​)​​


​​}​​


a函数内抛出了错误,被外围事先defer的函数recover到,接着就能对错误进行处理了。用这样的方式来改造上面用err处理的代码看看。

​​package​​         ​​main​​       





​​import​​ ​​ (​​


​​"log"​​


​​)​​





​​func​​ ​​ a() {​​


​​b()​​


​​c()​​





​​panic(​​ ​​"a内错误"​​ ​​)​​


​​return​​


​​}​​





​​func​​ ​​ b() {​​


​​panic(​​ ​​"b内错误"​​ ​​)​​


​​}​​





​​func​​ ​​ c() (err error) {​​


​​panic(​​ ​​"c内错误"​​ ​​)​​


​​}​​





​​func​​ ​​ main() {​​


​​defer​​ ​​func​​ ​​() {​​


​​if​​ ​​r := recover(); r != nil {​​


​​log.Printf(​​ ​​"Runtime error caught: %v"​​ ​​, r)​​


​​}​​


​​}()​​





​​a()​​


​​}​​


可以看到整个代码都简洁了很多,当然这里的代码比较简单可能看不出什么太大效果,在业务较为繁杂、经常要做各种校验的时候就可以显现出简洁了。

在开发api接口项目的时候,我会封装好recover的方法用来处理内部返回的错误信息,然后统一输出到客户端,感觉便捷很多。