golang工具值generate

发布时间 2023-09-15 09:43:58作者: X-Wolf

 

示例:

大家经常碰到命名错误码、状态码的同时,又要同步写码对应的翻译,有没有感觉很无聊。这里举一个例子:

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 arg2command可以是在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查看

 

注意点:

  1. go:generate前面只能使用//注释,注释必须在行首,前面不能有空格且//go:generate之间不能有空格!!!
  2. 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