go generate 为枚举类型生成字符串描述方法
作者:matrix 被围观: 4 次 发布时间:2024-08-10 分类:Golang | 无评论 »
go generate
命令可以方便的为自动生成源代码,利用官方的stringer
库来完成
安装stringer工具
如果本地已经安装,跳过
代码语言:javascript复制 go get -u golang.org/x/tools/cmd/stringer
Case
main.GO
代码语言:javascript复制package main
import "fmt"
type UserStatus int
const (
Active UserStatus = 40
Inactive UserStatus = 1
Pending UserStatus = 9
Other = Inactive
)
上面定义的常量类型UserStatus
,原始类型为 int 值,每次使用 fmt.Print打印会只显示数字,可读性会很差。
那怎么让fmt.Print输出对应的描述?
自定义结构体String()
方法,打印时会自动调用
...
func (s UserStatus) String() string {
switch s {
case Active:
return "Active"
case Inactive:
return "Inactive"
case Pending:
return "Pending"
default:
return "Other"
}
}
func main(){
var a UserStatus = Active
fmt.Println(a) //Active
}
定义go:generate
上面手动编写的确可以,但如果有状态值调整后续维护会很麻烦,结合go:generate
能自动生成String()方法
定义特定开头规则的注释//go:generate
,这样go generate
可以自动识别
//go:generate go run golang.org/x/tools/cmd/stringer -type=UserStatus
type UserStatus int
说明:
go:generate
表示GO generate命令标记
go run golang.org/x/tools/cmd/stringer
表示stringer的执行命令,如果本地已经全局安装了其实也可以替换为stringer
。但你得确保环境变量能够读取到它
-type
参数用于指定自定义的类型UserStatus
执行go:generate
代码语言:javascript复制go generate main.go
不指定main.go 文件,generate命令会查找所有包含 //go:generate
指令的文件,并执行这些指令后面的命令。这个例子就会运行 stringer -type=UserStatus
,为 UserStatus 类型生成一个新的 Go 文件userstatus_string.go
,包含 String() 方法的实现。
自动生成的userstatus_string.go
文件
// Code generated by "stringer -type=UserStatus"; 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[Active-40]
_ = x[Inactive-1]
_ = x[Pending-9]
}
const (
_UserStatus_name_0 = "Inactive"
_UserStatus_name_1 = "Pending"
_UserStatus_name_2 = "Active"
)
func (i UserStatus) String() string {
switch {
case i == 1:
return _UserStatus_name_0
case i == 9:
return _UserStatus_name_1
case i == 40:
return _UserStatus_name_2
default:
return "UserStatus(" strconv.FormatInt(int64(i), 10) ")"
}
}
自动生成的代码中String()
其实都大同小异,但是他考虑到了其他值。
并且_()
匿名的函数内置逻辑用例可以起到防止枚举值被修改的问题,比如这里Active
值被调整后会导致x[Active-40]
取到非下标值导致编译失败 So Nice~
并且标注了DO NOT EDIT.
这样以后维护和构建过程更简单明了。
参考:
https://medium.com/@dadcod/6-unique-and-lesser-known-go-techniques-9821be24972b
https://www.jvt.me/posts/2022/06/15/go-tools-dependency-management/
stringer 源码: https://cs.opensource.google/go/x/tools/ /master:cmd/stringer/stringer.go