Home > Article > Backend Development > Guys, how do you use enumerations in Go projects?
Enumeration is a very important data type, in
java
,C
Language and other mainstream programming languages support enumeration types, but there are no enumeration types in Go language. Is there any alternative? In this article, let’s talk about this matter;
We take the java
language as an example, inJDK1.5
There was no enumeration type before. We usually use int
constants to represent enumerations. The general usage is as follows:
public static final int COLOR_RED = 1; public static final int COLOR_BLUE = 2; public static final int COLOR_GREEN = 3;
Use int
Types may have the following hidden dangers:
final
就会造成值被篡改的风险;int
型数字并不知道其具体含义于是乎我们就想到用常量字符来表示,代码就变成了这样:
public static final String COLOR_RED = "RED"; public static final String COLOR_BLUE = "BLUE"; public static final String COLOR_GREEN = "GREEN";
这样也同样存在问题,因为我们使用的常量字符,那么有些程序猿不按套路出牌就可以使用字符串的值进行比较,这样的代码会被不断模仿变得越来越多的,然后山就出现了;
所以我们迫切需要枚举类型的出现来起到约束的作用,假设使用一个枚举类型做入参,枚举类型就可以限定沙雕用户不按套路传参,这样就可以怼他了,哈哈~;
使用枚举的代码就可以变成这样,传了枚举之外的类型都不可以了;
public class EnumClass { public static void main(String [] args){ Color color = Color.RED; convert(color); System.out.println(color.name()); } public static void convert(Color c){ System.out.println(c.name()); } } enum Color{ RED,BLUE,GREEN; }
Go语言就没有枚举类型,我们该使用什么方法来替代呢?
枚举通常是一组相关的常量集合,Go
语言中有提供常量类型,所以我们可以使用常量来声明枚举,但也同样会遇到上述的问题,起不到约束的作用,所以为了起到约束我们可以使用Go
语言另外一个知识点 -- 类型定义,Go
语言中可以使用type
关键字定义不同的类型,我们可以为整型、浮点型、字符型等定义新的类型,新的类型与原类型转换需要显式转换,这样在一定程度上也起到了约束的作用,我们就可以用Go
语言实现如下枚举:
type OrderStatus int const ( CREATE OrderStatus = iota + 1 PAID DELIVERING COMPLETED CANCELLED ) func main() { a := 100 IsCreated(a) }
上面的代码就会报错:
./main.go:19:12: cannot use a (variable of type int) as type OrderStatus in argument to IsCreated
定义新的类型可以起到约束作用,比如我们要检查状态机,入参限定了必须是OrderStatus类型,如果是int
类型就会报错。
上面我们的枚举实现方式只能获取枚举值,获取不到其映射的字面意思,所以我们可以优化一下,实现String
方法,使用官方提供的cmd/string来快速实现,代码如下:
//go:generate stringer -type=OrderStatus type OrderStatus int const ( CREATE OrderStatus = iota + 1 PAID DELIVERING COMPLETED CANCELLED )
执行命令go generate ./...
生成orderstatus_string.go文件:
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[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 (i OrderStatus) String() string { i -= 1 if i < 0 || i >= OrderStatus(len(_OrderStatus_index)-1) { return "OrderStatus(" + strconv.FormatInt(int64(i+1), 10) + ")" } return _OrderStatus_name[_OrderStatus_index[i]:_OrderStatus_index[i+1]] }
Go
语言使用protobuf会生成对应的枚举代码,我们发现其中也是使用定义新的类型的方式来实现的,然后在封装一些方法,我们来赏析一下protobuf生成的枚举代码:
const ( CREATED OrderStatus = 1 PAID OrderStatus = 2 CANCELED OrderStatus = 3 ) var OrderStatus_name = map[int32]string{ 1: "CREATED", 2: "PAID", 3: "CANCELED", } var OrderStatus_value = map[string]int32{ "CREATED": 1, "PAID": 2, "CANCELED": 3, } func (x OrderStatus) Enum() *OrderStatus { p := new(OrderStatus) *p = x return p } func (x OrderStatus) String() string { return proto.EnumName(OrderStatus_name, int32(x)) } func (x *OrderStatus) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(OrderStatus_value, data, "OrderStatus") if err != nil { return err } *x = OrderStatus(value) return nil }
虽然Go语言没有提供枚举类型,但是我们也可以根据Go
语言的两个特性:常量和定义新类型来实现枚举,方法总比困难多吗,开源库是优秀的,我们往往可以从高手那里里学习很多,记住,请永远保持一个学徒之心;
The above is the detailed content of Guys, how do you use enumerations in Go projects?. For more information, please follow other related articles on the PHP Chinese website!