无论你今天怎么用力,明天的落叶还是会飘下来,世上有很多事是无法提前的,活在当下,正向提升。
1. 前言
开发中经常有定义错误码这样的需求,错误码唯一标识具体的错误信息。另外还需要设置每个错误的具体描述。比如在HTTP协议中,200表示 "OK",404表示"Not Found",那如何在我们的项目中添加这样的错误码呢?手动?还是自动?
2. 手动的情况
package main import "fmt" type ErrCode int // 定义错误码 const ( ERR_OK ErrCode = iota //请求OK ERR_PARAMS //请求参数出错 ERR_TiMEOUT //请求超时 ) // 定义错误码与描述信息的映射 var mapErrDesc = map[ErrCode]string { ERR_OK: "OK", ERR_PARAMS: "无效参数", ERR_TiMEOUT: "超时", } //实现String() 这样print会调用String() func (e ErrCode) String() string { return GetDescription(e) } // 根据错误码返回描述信息 func GetDescription(errCode ErrCode) string { if desc, exist := mapErrDesc[errCode]; exist { return desc } return fmt.Sprintf("error code: %d", errCode) } func main() { fmt.Println(ERR_TiMEOUT) if ERR_OK == 0 { fmt.Println(ERR_OK) } }
输出:
超时 OK
看到了吗,我们既可以拿错误码进行业务逻辑判断,又可以按照我们想要的方式输出,但是这样有个问题就是每次增加错误码时,都需要修改mapErrDesc,有时候可能会忘。另外,错误描述在注释和mapErrDesc都出现了。那么能不能只写注释,然后使用工具自动生成我们想要的代码呢?
3. 自动
package main import "fmt" type ErrCode int //go:generate stringer -type ErrCode -linecomment -output code_string.go const ( ERR_OK ErrCode = iota //请求OK ERR_PARAMS//请求参数出错 ERR_TiMEOUT//请求超时 ) func main() { fmt.Println(ERR_OK) fmt.Println(ERR_PARAMS) fmt.Println(ERR_TiMEOUT) if ERR_OK == 0 { fmt.Println(ERR_OK) } if ERR_TiMEOUT == 2 { fmt.Println(ERR_TiMEOUT) } }
在同级目录下终端输入go generate
就会自动生成code_string.go,然后我们运行go run main.go
输出:
请求OK 请求参数出错 请求超时 请求OK 请求超时
go generate
是 Go 自带的工具。使用命令go generate执行。但是前提就是在你的错误码常量之前增加以下代码,如下所示:
//go:generate stringer -type ErrCode -linecomment -output code_string.go
go generate利用stringer生成字符串描述,默认stringer有两种模式,默认是根据变量/常量名来生成。
- 选项-type指定stringer命令作用的类型名,这里是ErrCode
- 选项-output指定输出文件名,这里是code_string.go
- 选项-linecomment指定后面的注释作为错误描述,比如"超时"
stringer可以自己安装,安装目录如下:
$ go get golang.org/x/tools/cmd/stringer
我们看下生成的code_string.go:
// Code generated by "stringer -type ErrCode -linecomment -output code_string.go"; DO NOT EDIT. package main import "strconv" func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[ERR_OK-0] _ = x[ERR_PARAMS-1] _ = x[ERR_TiMEOUT-2] } const _ErrCode_name = "请求OK请求参数出错请求超时" var _ErrCode_index = [...]uint8{0, 8, 26, 38} func (i ErrCode) String() string { if i < 0 || i >= ErrCode(len(_ErrCode_index)-1) { return "ErrCode(" + strconv.FormatInt(int64(i), 10) + ")" } return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]] }
我们看到它是节约存储错误码信息以及实现了String方法,这样就比我们自己实现好多了。
4. 小结
通过这种自动生成的方式,我们开发人员再也不用担心维护那么多错误码描述信息了,只要你的注释是ok的,那么你就直接使用错误码常量就行,哪里作为判断,哪里作为展示输出就特别方便了。
5. 关注公众号
微信公众号:堆栈future