在Go语言里,枚举通常是通过自定义类型和常量组合实现的,默认情况下枚举值打印出来是数字,要实现将枚举值转换为对应名称字符串的功能,常规做法是手动编写String方法。不过手动维护这种方式在枚举值较多或者频繁修改时很容易出现问题,我们可以通过工具自动生成对应的代码,无需手动编写String方法就能获得枚举名称映射能力。

常规手动实现String方法的方式
我们先来看一下传统的手动实现方式,假设我们定义一个表示季节的枚举类型:
package main
import "fmt"
// Season 季节枚举类型
type Season int
const (
Spring Season = iota
Summer
Autumn
Winter
)
// String 手动实现的String方法,返回枚举对应的名称
func (s Season) String() string {
switch s {
case Spring:
return "Spring"
case Summer:
return "Summer"
case Autumn:
return "Autumn"
case Winter:
return "Winter"
default:
return "Unknown"
}
}
func main() {
var s Season = Summer
fmt.Println(s) // 输出 Summer
}
这种方式的问题在于每次新增或者修改枚举值的时候,都需要同步修改String方法里的逻辑,否则会出现映射错误的情况。
使用stringer工具自动生成映射代码
Go官方提供了stringer工具,可以自动为枚举类型生成String方法,不需要我们手动编写。首先我们需要安装这个工具:
go install golang.org/x/tools/cmd/stringer@latest
安装完成后,我们只需要在枚举定义的代码里添加一行注释标记,告诉stringer需要为哪个类型生成String方法:
package main import "fmt" // Season 季节枚举类型 type Season int const ( Spring Season = iota Summer Autumn Winter ) //go:generate stringer -type=Season
然后我们在当前代码目录下执行生成命令:
go generate
执行完成后,会自动生成一个season_string.go的文件,里面已经包含了完整的String方法实现,我们不需要手动编写任何相关逻辑。生成的代码大致内容如下:
// Code generated by "stringer -type=Season"; 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[Spring-(0)]
_ = x[Summer-(1)]
_ = x[Autumn-(2)]
_ = x[Winter-(3)]
}
const _Season_name = "SpringSummerAutumnWinter"
var _Season_index = [...]uint8{0, 6, 12, 18, 24}
func (i Season) String() string {
if i < 0 || i >= Season(len(_Season_index)-1) {
return "Season(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Season_name[_Season_index[i]:_Season_index[i+1]]
}
此时我们再运行之前的main函数,就可以正常输出枚举的名称字符串了,而且后续如果新增或者修改枚举值,只需要重新执行go generate命令就可以更新生成的逻辑,不需要手动修改任何代码。
stringer工具的其他常用参数
stringer工具还支持一些常用的参数,可以根据实际需求调整生成的代码:
-output:指定生成的文件路径和名称,默认是类型名小写加_string.go-linecomment:如果枚举常量后面有行注释,会将注释作为String方法的返回值,而不是常量名
比如我们使用-linecomment参数,修改枚举定义:
package main import "fmt" // Season 季节枚举类型 type Season int const ( Spring Season = iota // 春 Summer // 夏 Autumn // 秋 Winter // 冬 ) //go:generate stringer -type=Season -linecomment重新执行
go generate后,生成的String方法会返回注释内容,比如Spring对应的返回值就是"春"。注意事项
使用stringer工具自动生成枚举名称映射的时候,需要注意以下几点:
- 枚举的基础类型必须是整数类型,否则stringer无法正常工作
- 不要手动修改自动生成的文件,避免下次生成的时候覆盖掉自己的修改内容
- 如果枚举值有重复的情况,stringer生成的逻辑可能会出现不符合预期的结果,需要确保枚举值唯一