后端的API从Java转到了Go,Go写起来言简意赅,很受欢迎。但Go带着C的风格,异常处理显得不够优雅。看了好几篇这方面的文章也没有一个满意的方案,后来自己做了一套方案,效果还可以,在这里介绍一下。
先看看Java的异常处理,在正常的程序流程里,一旦出现异常,就会马上终止原来的流程,把异常层层上报,直到异常被处理。程序里面就是 try -> throw -> catch -> finally 的过程。
再看C风格的异常处理,无论发生什么情况,函数都必须按照唯一的方式返回结果,所以很多函数在返回正常结果时还要额外返回一个error,收到这样的返回结果要先处理了error,再处理返回结果。代码里面到处是
if err != nil {
...
}
看着不美观,每次都要处理异常,调用的逻辑一旦复杂就容易失控了。
但很多文章总是强调panic是很危险的,会导致崩溃,error要分成各种各样等等。其实Go也提供了类似Java的异常处理机制,总结一下:
Java Go
throw panic
finally defer
catch recover
原来这样的func
func GetUser() (user User, err error)
其实这样写就好了,
func GetUser() (user User)
如果发生了异常情况,就直接panic(error),error的内容也可以自定义,调用的函数不需要特意去处理这个error,当成RuntimeException一样,这程序流程里面就不用到处写恶心的 if err != nil {...}
我们一般写的都是基于web的系统,只要加一个拦截器做异常处理,就不怕程序崩溃了。拦截器的核心内容就像这样
func Recover(ctx ) {
defer func() {
err := recover()
if err != null {
// handling error
}()
}
// forward the request
ctx.Next()
}
这个拦截器一般要第一个加载,保证整个request handling都有defer的覆盖。