Home >Backend Development >Golang >Guys, how do you use enumerations in Go projects?

Guys, how do you use enumerations in Go projects?

Golang菜鸟
Golang菜鸟forward
2023-08-04 17:25:08943browse

Preface

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;

Why do we need enumerations

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]]
}

protobuf中生成的枚举代码

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!

Statement:
This article is reproduced at:Golang菜鸟. If there is any infringement, please contact admin@php.cn delete