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

伙计,Go项目如何使用枚举?

时间:2023-03-18 16:47:13 科技观察

前言大家好,我是asong.枚举是一种非常重要的数据类型。Java、C等主流编程语言都支持,但Go语言中没有枚举类型。还有其他选择吗?在这篇文章中,我们来谈谈这件事;为什么有一个枚举?我们以java语言为例。JDK1.5之前没有枚举类型。我们通常使用int常量来表示枚举。一般用法如下:publicstaticfinalintCOLOR_RED=1;publicstaticfinalintCOLOR_BLUE=2;publicstaticfinalintCOLOR_GREEN=3;使用int类型存在以下隐患:不安全,如果声明不是final,值会被篡改;语义不够清晰,打印int类型的数字不知道它的具体含义,于是想到用常量字符来表示,代码变成这样:publicstaticfinalStringCOLOR_RED="RED";publicstaticfinalStringCOLOR_BLUE="BLUE";publicstaticfinalStringCOLOR_GREEN="GREEN";这也有问题,因为我们使用的是常量字符,那么有些程序员可以不按套路使用字符串的值进行比较,这样的代码就会不断的被仿的越来越多,然后出现石山;所以我们迫切需要枚举类型的出现来起到约束的作用。假设用一个枚举类型作为入参,枚举类型可以限制沙雕用户,不按套路传参数,打他一顿,哈哈~;使用枚举的代码可以变成这样,除了枚举以外的类型不能传;publicclassEnumClass{publicstaticvoidmain(String[]args){Colorcolor=Color.RED;转换(颜色);System.out.println(color.name());}publicstaticvoidconvert(Colorc){System.out.println(c.name());}}枚举颜色{红色、蓝色、绿色;}Go语言没有枚举类型。我们应该使用什么方法呢?定义新类型以实现枚举枚举通常是一组相关的常量。Go语言提供了常量类型,所以我们可以用常量来声明枚举,但是我们也会遇到上面的问题,无法约束,所以为了约束我们,我们可以利用Go语言的另一个知识点——类型定义。在Go语言中,我们可以使用type关键字来定义不同的类型。我们可以用整数、浮点数、字符来定义一个新的类型,新类型和原类型之间的转换需要显式转换,这也在一定程度上起到了约束的作用。我们可以使用Go语言实现如下枚举:typeOrderStatusintconst(CREATEOrderStatus=iota+1PAIDDELIVERINGCOMPLETEDCANCELLED)funcmain(){a:=100IsCreated(a)}上面的代码会报错:./main.go:19:12:不能使用(int类型的变量)作为IsCreated参数中的类型OrderStatus定义了一个可以充当约束的新类型。比如我们要查看状态机,入参必须是OrderStatus类型。如果是int类型,会报错。我们上面的枚举实现方法只能获取枚举值,不能获取其映射的字面意思,所以我们可以对其进行优化,实现String方法,使用官方的cmd/string可以快速实现。代码如下://go:generatestringer-type=OrderStatustypeOrderStatusintconst(CREATEOrderStatus=iota+1PAIDDELIVERINGCOMPLETEDCANCELLED)执行命令gogenerate./...生成orderstatus_string.go文件:import"strconv"func_(){//一个“无效的数组索引”编译器错误标志常量值已经改变。//重新运行stringer命令以再次生成它们。varx[1]struct{}_=x[CREATE-1]_=x[PAID-2]_=x[DELIVERING-3]_=x[COMPLETED-4]_=x[CANCELLED-5]}const_OrderStatus_name="CREATEPAIDDELIVERINGCOMPLETEDCANCELLED"var_OrderStatus_index=[...]uint8{0,6,10,20,29,38}func(iOrderStatus)String()string{i-=1ifi<0||我>=OrderStatus(len(_OrderStatus_index)-1){return"OrderStatus("+strconv.FormatInt(int64(i+1),10)+")"}return_OrderStatus_name[_OrderStatus_index[i]:_OrderStatus_index[i+1]]}protobuf生成枚举代码Go语言使用protobuf生成对应的枚举代码,我们发现也是通过定义一个新的类型来实现的,然后封装一些方法,我们来欣赏一下protobuf生成的枚举代码:const(CREATEDOrderStatus=1PAIDOrderStatus=2CANCELEDOrderStatus=3)varOrderStatus_name=map[int32]string{1:"CREATED",2:"PAID",3:"CANCELED",}varOrderStatus_value=map[string]int32{"CREATED":1,"PAID":2,"CANCELED":3,}func(xOrderStatus)Enum()*OrderStatus{p:=new(OrderStatus)*p=xreturnp}func(xOrderStatus)String()string{returnproto.EnumName(OrderStatus_name,int32(x))}func(x*OrderStatus)UnmarshalJSON(data[]byte)error{value,err:=proto.UnmarshalJONEnum(OrderStatus_value,data,"OrderStatus")iferr!=nil{returnerr}*x=OrderStatus(value)returnnil}总结虽然Go语言不提供枚举类型,我们也可以根据Go语言的两个特点来实现枚举:常量和定义新类型。是不是方法比难度还难?开源库很优秀,我们经常可以向专家学习有很多东西要学,切记,请永远保持一颗学徒的心