当前位置: 首页 > 科技观察

技巧分享:Go中如何实现枚举?

时间:2023-03-17 11:46:54 科技观察

本文转载自微信公众号《我的脑子是炸鱼》,作者陈建宇。转载本文请联系脑筋急转弯公众号。大家好,我是炸鱼。在日常的业务工程开发中,我们经常会有使用枚举值的诉求。枚举控制的不错,测试值的边界又传过去了。。。有小伙伴会说Go语言没有枚举的iota类型嘛,这篇文章还扯什么?公平地说,Go语言没有enum关键字。用过Protobuf等的朋友都知道,Go语言只支持“有限枚举”,我们也会用常量来定义,枚举值也需要有字面量映射。示例在某些业务场景中,无法满足我们的需求。示例如下:typeFishTypeintconst(AFishType=iotaBCD)funcmain(){fmt.Println(A,B,C,D)}输出结果为:“0123”。这时候我就懵了……枚举值除了key应该还有一个对应的值吧。即“0123”对应什么意思,是否应该输出“ABCD”但是Go语言没有直接支持,所以这不是枚举类型的完整实现。同时,假设我们传入一个超出FishType类型声明范围的枚举值,在Go语言中默认是没有控制的,会正常输出。上面的Go枚举实现在某些情况下是不完整的,不能成为严格意义上的枚举。使用String作为枚举如果我们想支持枚举值对应的输出,可以使用如下方法:typeFishTypeintconst(AFishType=iotaBCD)func(fFishType)String()string{return[...]string{"A","B","C","D"}[f]}运行程序:funcmain(){varfFishType=Afmt.Println(f)switchf{caseA:fmt.Println("大脑是炸鱼")案例B:fmt。Println("Remembertolike")default:fmt.Println("Don't,don't,don't...")}}输出结果:A的大脑是炸鱼我们可以使用String的默认约定Go中的method定义String方法的类型,默认输出时会调用。这样,在获取枚举值的同时,还可以获取其映射的字面意思。自动生成String但是每次手动写比较麻烦。在这方面,我们可以使用官方的cmd/string来快速实现。我们安装如下命令:goinstallsgolang.org/x/tools/cmd/stringer在想要的枚举值上设置go:generate命令://go:generatestringer-type=FishTypetypeFishTypeint在项目根目录下执行:gogenerate./...根目录下会生成fishtype_string.go文件:.├──fishtype_string.go├──go.mod├──go.sum└──main.gofishtype_string文件内容:packagemainimport"strconv"const_FishType_name="ABCD"var_FishType_index=[...]uint8{0,1,2,3,4}func(iFishType)String()string{ifi<0||i>=FishType(len(_FishType_index)-1){return"FishType("+strconv.FormatInt(int64(i),10)+")"}return_FishType_name[_FishType_index[i]:_FishType_index[i+1]]}生成的文件主要是根据枚举值和映射值。并对超出枚举值的场景进行判断:funcmain(){varf1FishType=Afmt.Println(f1)varf2FishType=Efmt.Println(f2)}executegorun。查看程序运行结果:$gorun.AFishType(4)总结在今天的文章中,我们介绍了如何用Go语言实现标准的枚举值。虽然有点麻烦,但总体来说难度不是太大。也有小伙伴在社区提出了“proposal:spec:addtypedenumsupport”的提案。我相信将来总有一天Go本身会支持enum(枚举)。