示例:
大家经常碰到命名错误码、状态码的同时,又要同步写码对应的翻译,有没有感觉很无聊。这里举一个例子:
package main
import "fmt"
// 定义错误码
const (
ERR_CODE_OK = 0 // OK
ERR_CODE_INVALID_PARAMS = 1 // 无效参数
ERR_CODE_TIMEOUT = 2 // 超时
)
// 定义错误码与描述信息的映射
var mapErrDesc = map[int]string{
ERR_CODE_OK: "OK",
ERR_CODE_INVALID_PARAMS: "无效参数",
ERR_CODE_TIMEOUT: "超时",
}
// 根据错误码返回描述信息
func GetDescription(errCode int) string {
if desc, exist := mapErrDesc[errCode]; exist {
return desc
}
return fmt.Sprintf("error code: %d", errCode)
}
func main() {
fmt.Println(GetDescription(ERR_CODE_OK))
}
这是一种重复性操作,没有什么技术含量,另外很可能忘记写映射。我只想写错误码,对应的描述信息直接用注释里的就行,所以这里介绍一下对应的工具。
go generate
go有很多工具,大家可以通过go命令查看。
go generate
是 Go 自带的工具。使用命令go generate
执行。go generate
是利用源代码中的注释工作的。格式如下:
//go:generate command arg1 arg2
这样在同一个目录下执行命令go generate
就会自动运行命令command arg1 arg2
。command
可以是在PATH
中的任何命令,应用非常广泛。配合stringer
命令可以为给定类型生成String
方法,就可以实现我们的想法。
安装stringer
stringer不是Go自带工具,需要手动安装。执行如下命令即可
go get golang.org/x/tools/cmd/stringer
使用
有两种执行方案,
一种是在errcode中,增加注释//go:generate stringer -type ErrCode -linecomment
另一种是直接命令行执行stringer -type ErrCode -linecomment
执行完毕会发现自动生成新文件
关于stringer的命令,大家可以通过stringer -h查看
注意点:
-
go:generate
前面只能使用//
注释,注释必须在行首,前面不能有空格且//
与go:generate
之间不能有空格!!! -
go:generate
可以在任何 Go 源文件中,最好在类型定义的地方。
自动化:
makefile 中:
all:
go generate && go build .
demo文件: errcode.go源文件,errcode_test.go测试文件 errcode_string.go生成文件
errcode.go
package errcode
// ErrCode 表示错误码
type ErrCode int
//go:generate stringer -type ErrCode -linecomment -output code_string.go
// -type指定类型
// -output code_string.go 指定生成的文件名称
// -linecomment 将注释名称作为错误描述
// 定义错误码
const (
ERR_CODE_OK ErrCode = 0 // OK
ERR_CODE_INVALID_PARAMS ErrCode = 1 // 无效参数
ERR_CODE_TIMEOUT ErrCode = 2 // 超时
// ...
)
errcode_test.go
package errcode
import "testing"
func TestCode(t *testing.T) {
cases := []struct {
errCode ErrCode
expect string
}{
{ERR_CODE_OK, "OK"},
{ERR_CODE_INVALID_PARAMS, "无效参数"},
{ERR_CODE_TIMEOUT, "超时"},
}
for _, testCase := range cases {
if testCase.errCode.String() != testCase.expect {
t.Errorf("error code %d description inconsistant actual:%s expect:%s", int(testCase.errCode), testCase.errCode, testCase.expect)
}
}
}
errcode_string.go
// Code generated by "stringer -type ErrCode -linecomment"; DO NOT EDIT.
package errcode
import "strconv"
const _ErrCode_name = "OK无效参数超时"
var _ErrCode_index = [...]uint8{0, 2, 14, 20}
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]]
}
执行测试:
go generate
or
go generate ./...
go test