首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Go语言学习四——异常处理

程序就像汽车,一旦上路,难免会有各种大大小小的突发情况:路上突然闯出一个行人、没油了、零部件故障甚或剐蹭追尾、车毁人亡。现代的汽车已经针对各种情况作出了不同的预案:鸣笛警示行人、将近没油时进行提示、汽车启动时检查核心部件,在最糟糕的情况下,也会弹出安全气囊尽量减少损伤。更智能的无人驾驶技术甚至可以自动减速、主动避让行人。

好的程序语言就像好的汽车,为我们提供了多层次的安全预案与安全保障。早期的C语言并没有直接提供语言层面的异常处理,更多需要程序员自己判断异常情况并返回errorCode,或者使用goto语句跳转到错误处理逻辑进行错误处理;经典的面向对象语言如Java通常提供了更完备的错误处理机制:明确不同的错误类型,并提供语言级别的异常捕获(try-catch-finally)机制,在很大程度上减轻了程序员的负担,提供了程序的健壮性。

作为一门更年轻也非常有个性的编程语言,Go语言借助自己函数多返回值、函数式编程以及灵活的接口等特性,提供了非常优雅的异常处理方式。

一. 异常接口

Go语言内置了基础的error数据类型,定义如下:

可以看出,error类型是一个接口,其中声明了一个方法,用来获取错误信息。

基于这个接口,我们可以声明自己的error类型,如下:

基于error扩展的错误类型可以包含更多的错误信息,便于更好的分析、定位问题。

有了error类型之后,我们在遇到错误时,就可以返回error了,由于Go语言中的函数支持返回多个值,因此,通常函数设计时都会连同正常结果与错误信息一起返回,如下:

二. defer

程序中一些特殊的操作需要在处理完成后执行清理,例如打开文件、网络连接后需要关闭,但是一旦程序在执行过程中出错,这些清理操作很有可能得不到执行,造成文件句柄得不到关闭,网络连接得不到释放的情况,对系统整体的性能及稳定性都有很大影响。为了解决这个问题,Go引入了defer关键字,在作用上有点类似于java中的。我们直接看一下上面代码中用到的方法代码:

函数中在打开文件后声明了defer语句用于关闭文件,则即使函数在后面执行过程中出错,该语句也会被执行。每当声明一个defer语句时,相当于向函数注册一个延迟执行命令,等函数执行完毕或者异常退出时将执行这些指令。

此外,当一个函数中定义了多个defer语句时,函数退出时将按照从后往前的顺序执行这些panic语句。我们再来看一个例子:

我们在方法中故意写了一个空指针异常,运行结果如下:

"testDefer 3"没有得到执行,因为在执行到时就以及异常了,只会执行之前已经注册的defer语句。

三. panic

当程序遇到严重的系统问题,需要停止运行时,可以使用系统内置的函数来报告错误。这通常可以应用在程序启动时执行初始化的阶段,因为一旦初始化失败,系统应当停止运行,否则错误初始化的程序将可能导致更多未知的错误。

当程序执行panic时,正常的执行流程将立即结束,但是函数中声明的defer语句仍将继续执行,之后将按照调用链条逐层向上执行panic流程。

一个简单的示例:

运行结果如下:

四. recover

通常,在程序中遇到错误并执行了panic方法后,程序会在执行完defer语句后退出,但是有时我们并不希望程序退出,而是希望能捕获到异常信息,打印日志或者触发报警,但程序依然继续运行。方法就是用于这个目的。方法通常放在defer语句中,以保证一定会得到执行,如下:

我们在方法的最前面声明了函数,并在其中用方法捕获异常,这样,即使捕获到异常,也只是打印一条错误信息,不会导致程序退出。执行结果如下:

五. 小结

以上,我们列举了Go语言在异常处理方面的一些特性,通过这些简单的测试代码,我们可以大致看出Go语言的异常处理方式:

通过内置的错误类型来记录已识别的异常信息,并返回给调用函数

通过方法来捕捉未识别的异常信息,并结束异常,使程序继续运行

通过主动结束程序

通过语句强制程序在退出前执行必要的清理

参考资料

许式伟:《Go语言编程》

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180618G18PSJ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券