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

次の例: 構造体の埋め込み.