Go 示例: 枚举

枚举类型(枚举)是和类型的一种特殊情况。枚举是一种具有固定数量可能值的类型,每个值都有一个不同的名称。Go 语言没有将枚举类型作为一种独立的语言特性,但可以使用现有的语言习惯来轻松实现枚举。

package main
import "fmt"

我们的枚举类型 ServerState 的底层类型为 int

type ServerState int

ServerState 的可能值定义为常量。特殊的关键字 iota 会自动生成连续的常量值;在本例中为 0、1、2 等等。

const (
    StateIdle = iota
    StateConnected
    StateError
    StateRetrying
)

通过实现 fmt.Stringer 接口,可以打印出 ServerState 的值或将其转换为字符串。

如果可能的值很多,这可能会很麻烦。在这种情况下,可以使用 stringer 工具go:generate 结合使用来自动执行此过程。有关更详细的说明,请参见 这篇文章

var stateName = map[ServerState]string{
    StateIdle:      "idle",
    StateConnected: "connected",
    StateError:     "error",
    StateRetrying:  "retrying",
}
func (ss ServerState) String() string {
    return stateName[ss]
}

如果我们有一个 int 类型的变量,则无法将其传递给 transition - 编译器会抱怨类型不匹配。这为枚举提供了一定程度的编译时类型安全。

func main() {
    ns := transition(StateIdle)
    fmt.Println(ns)
    ns2 := transition(ns)
    fmt.Println(ns2)
}

transition 模拟了服务器的状态转换;它接受现有状态并返回一个新状态。

func transition(s ServerState) ServerState {
    switch s {
    case StateIdle:
        return StateConnected
    case StateConnected, StateRetrying:

假设我们在这里检查一些谓词以确定下一个状态…

        return StateIdle
    case StateError:
        return StateError
    default:
        panic(fmt.Errorf("unwknown state: %s", s))
    }
    return StateConnected
}
$ go run enums.go
connected
idle

下一个示例:结构体嵌入