关于go:伙计Go项目怎么使用枚举

39次阅读

共计 2951 个字符,预计需要花费 8 分钟才能阅读完成。

前言

哈喽,大家好,我是 asong。枚举是一种很重要的数据类型,在javaC 语言等支流编程语言中都反对了枚举类型,然而在 Go 语言中却没有枚举类型,那有什么代替计划吗?本文咱们来聊一聊这个事件;

为什么要有枚举

咱们以 java 语言为例子,在 JDK1.5 之前没有枚举类型,咱们通常会应用 int 常量来示意枚举,个别应用如下:

public static final int COLOR_RED = 1;
public static final int COLOR_BLUE = 2;
public static final int COLOR_GREEN = 3;

应用 int 类型会存在以下隐患:

  • 不具备安全性,申明时如果没有应用 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 语言的两个个性:常量和定义新类型来实现枚举,办法总比艰难多吗,开源库是优良的,咱们往往能够从高手那里里学习很多,记住,请永远放弃一个学徒之心;

好啦,本文到这里就完结了,我是asong,咱们下期见。

欢送关注公众号:Golang 梦工厂

正文完
 0