【golang】枚举的最佳实践

11,104 阅读2分钟

前言

go语言不像其他高级语言(如Java),没有内置枚举类型。那go语言中如何玩枚举呢?

使用const定义枚举

枚举本质就是一系列常量。所以,go语言中可以使用const来定义枚举,如:

const (
   Male   = "男性"
   Female = "女性"
)

最佳实践

  1. 可以使用类型别名,让常量看起来更直观:根据类型就能明确知道该常量是啥枚举。比如:
type Gender = string

const (
   Male   Gender = "男性"
   Female Gender = "女性"
)

通过类型别名可以很直观、很明确地知道MaleFemale两个常量是性别枚举。

  1. 如果这个枚举有自定义方法,可以使用type关键字新建枚举类型,然后为该枚举类型定义方法。如:
type Gender string

const (
   Male   Gender = "男性"
   Female Gender = "女性"
)

func (g *Gender) String() string {
   switch *g {
   case Male:
      return "男性"
   case Female:
      return "女性"
   default:
      return ""
   }
}

好处:

  • 定义了枚举类型,更直观、更清晰
  • 可以给枚举类型自定义方法
  • 因为是新类型,可以触发编辑器的类型检查
  1. 如果是整型常量,可以使用iota常量计数器。如:
type Gender int

const (
   Male   Gender = iota
   Female
)

源码大赏

看看好的go项目如何玩枚举的

比如,看看google.golang.org/grpc/codes里的gRPC的错误码是怎么定义的:

type Code uint32

const (
   OK                 Code = 0
   Canceled           Code = 1
   Unknown            Code = 2
   InvalidArgument    Code = 3
   DeadlineExceeded   Code = 4
   AlreadyExists      Code = 6
   PermissionDenied   Code = 7
   ResourceExhausted  Code = 8
   FailedPrecondition Code = 9
   Aborted            Code = 10
   OutOfRange         Code = 11
   Unimplemented      Code = 12
   Internal           Code = 13
   Unavailable        Code = 14
   DataLoss           Code = 15
   Unauthenticated    Code = 16
   _maxCode                = 17
)

func (c Code) String() string {
   switch c {
   case OK:
      return "OK"
   case Canceled:
      return "Canceled"
   case Unknown:
      return "Unknown"
   case InvalidArgument:
      return "InvalidArgument"
   case DeadlineExceeded:
      return "DeadlineExceeded"
   case NotFound:
      return "NotFound"
   case AlreadyExists:
      return "AlreadyExists"
   case PermissionDenied:
      return "PermissionDenied"
   case ResourceExhausted:
      return "ResourceExhausted"
   case FailedPrecondition:
      return "FailedPrecondition"
   case Aborted:
      return "Aborted"
   case OutOfRange:
      return "OutOfRange"
   case Unimplemented:
      return "Unimplemented"
   case Internal:
      return "Internal"
   case Unavailable:
      return "Unavailable"
   case DataLoss:
      return "DataLoss"
   case Unauthenticated:
      return "Unauthenticated"
   default:
      return "Code(" + strconv.FormatInt(int64(c), 10) + ")"
   }
}

缺陷

在Java中,每个枚举有一个类,如性别枚举Gender类,可以直接Gender.XXX就能很方便地访问性别枚举了,也能很清晰地知道有哪些枚举值。
而在go里面就没有这么方便了,也不太好管理枚举。