前言
go语言不像其他高级语言(如Java),没有内置枚举类型。那go语言中如何玩枚举呢?
使用const定义枚举
枚举本质就是一系列常量。所以,go语言中可以使用const来定义枚举,如:
const (
Male = "男性"
Female = "女性"
)
最佳实践
- 可以使用类型别名,让常量看起来更直观:根据类型就能明确知道该常量是啥枚举。比如:
type Gender = string
const (
Male Gender = "男性"
Female Gender = "女性"
)
通过类型别名可以很直观、很明确地知道Male和Female两个常量是性别枚举。
- 如果这个枚举有自定义方法,可以使用
type关键字新建枚举类型,然后为该枚举类型定义方法。如:
type Gender string
const (
Male Gender = "男性"
Female Gender = "女性"
)
func (g *Gender) String() string {
switch *g {
case Male:
return "男性"
case Female:
return "女性"
default:
return ""
}
}
好处:
- 定义了枚举类型,更直观、更清晰
- 可以给枚举类型自定义方法
- 因为是新类型,可以触发编辑器的类型检查
- 如果是整型常量,可以使用
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里面就没有这么方便了,也不太好管理枚举。