深入剖析:一套在 Go 中传递、返回、暴露错误,便于回查的解决方案作者:andruzhang,腾讯 IEG 后台开发工程师
在后台开发中,针对错误处理,有三个维度的问题需要解决:
【go语言宏定义 go语言 %v】一个面向过程的函数,在不同的处理过程中需要 handle 不同的错误信息;一个面向对象的函数 , 针对一个操作所返回的不同类型的错误,有可能需要进行不同的处理 。此外,在遇到错误时 , 也可以使用断言的方式,快速中止函数流程,大大提高代码的可读性 。
在许多高级语言中都提供了 try ... catch 的语法,函数内部可以通过这种方案,实现一个统一的错误处理逻辑 。而即便是 C 这种 “中级语言” 虽然没有,但是程序员也可以使用宏定义的方式,来实现某种程度上的错误断言 。
但是,对于 Go 的情况就比较尴尬了 。
我们先来看断言,我们的目的是,仅使用一行代码就能够检查错误并终止当前函数 。由于没有 throw,没有宏,如果要实现一行断言 , 有两种方法 。
第一种是把 if 的错误判断写在一行内,比如:
第二种方法是借用 panic 函数,结合 recover 来实现:
这两种方法都值得商榷 。
首先,将 if 写在同一行内的问题有:
至于第二种方法 , 我们要分情况看;
不过使用 panic 来断言的方案 , 虽然在业务逻辑中基本上不用,但在测试场景下则是非常常见的 。测试嘛,用牛刀有何不可?稍微大一点的系统开销也没啥问题 。对于 Go 来说,非常热门的单元测试框架goconvey就是使用 panic 机制来实现单元测试中的断言,用的人都说好 。
综上,在 Go 中 , 对于业务代码,笔者不建议采用断言 , 遇到错误的时候建议还是老老实实采用这种格式:
而在单测代码中,则完全可以大大方方地采用类似于 goconvey 之类基于 panic 机制的断言 。
众所周知 Go 是没有 try ... catch 的,而且从官方的态度来看,短时间内也没有考虑的计划 。但程序员有这个需求呀 。笔者采用的方法,是将需要返回的 err 变量在函数内部全局化,然后结合 defer 统一处理:
这种方案要特别注意变量作用域问题.比如前面的 if err = DoSomething(); err != nil { 行,如果我们将 err = ... 改为 err := ...,那么这一行中的 err 变量和函数最前面定义的 (err error) 不是同一个变量 , 因此即便在此处发生了错误,但是在 defer 函数中无法捕获到 err 变量了 。
在 try ... catch 方面,笔者其实没有特别好的方法来模拟 , 即便是上面的方法也有一个很让人头疼的问题:defer 写法导致错误处理前置,而正常逻辑后置了 , 从可读性的角度来说非常不友好 。因此也希望读者能够指教 。同时还是希望 Go 官方能够继续迭代,支持这种语法 。
这一点在 Go 里面,一开始看起来还是比较统一的,这就是 Go 最开始就定义的 error 类型,以系统标准的方式,统一了进程内函数级的错误返回模式 。调用方使用 if err != nil 的统一模式,来判断一个调用是不是成功了 。
但是随着 Go 的逐步推广,由于 error 接口的高自由度,程序员们对于 “如何判断该错误是什么错误” 的时候,出现了分歧 。
在 Go 1.13 之前,对于 error 类型的传递,有三种常见的模式:
这个流派很简单,就是将各种错误信息直接定义为一个类枚举值的模式,比如:
当遇到相应的错误信息时,直接返回对应的 error 类枚举值就行了 。对于调用方也非常方便,可以采用 switch - case 来判断错误类型:
推荐阅读
- 街机飞行优秀游戏,街机 你所不知道的海量街机经典飞行类街机游戏汇总
- css如何设置消息边框,css实现聊天对话框
- 直播风衣讲解话术,直播风衣讲解话术大全
- linux命令挂在存储 linux存放基本命令
- c语言计算器程序怎么打,c语言设计一个简单的计算器程序
- 特别肝的模拟游戏,肝类游戏推荐
- c语言ln函数绝对值 c语言表示ln函数
- 长虹电视显示超时怎么办,长虹电视电源开关在哪里
- excel表格怎么全屏2003,excel表格怎么全屏打印