Tech

GoでEnumを表現する2つのパターン

最終更新:2026.03.02

Goには、Pythonなどの言語にあるような厳密なEnum型が存在しません。
そのため、独自の型定義と定数を組み合わせてEnumを表現するのが一般的です。

今回は、実務でよく使われる2つの表現パターンについて紹介します。

【パターン1】 iota を活用した連番定義

iotaは、定数ブロック内で連番を自動的に割り振るための仕組みです。(Goに備わっている標準機能です)

type ErrorCode int

const (
    BadRequest ErrorCode = iota + 1   // 1
    Required                          // 2
    InvalidChars                      // 3
    InternalError                     // 4
)

iotaの初期値について

Goの整数型のゼロ値は0です。
未初期化の変数と明示的な値を区別するため、iota + 1として1から開始するのが一般的なプラクティスです。

定義したEnum値に対して文字列を返したい場合は、以下のように String() メソッドを定義します。

func (e ErrorCode) String() string {
    switch e {
    case BadRequest:
        return "BadRequest"
    case Required:
        return "Required"
    case InvalidChars:
        return "InvalidChars"
    case InternalError:
        return "InternalError"
    default:
        return fmt.Sprintf("ErrorCode(%d)", e)
    }
}

これにより、fmt.Printlnなどで出力する際に、数値ではなく意味のある文字列として扱えるようになります。

【パターン2】 mapベースで管理していく

定数で定義した値をキーとして、対応するメッセージをmapに格納する方法です。
フォーマット可能な文字列や複雑なメタデータを関連づけたい場合に有効なパターンになります。

基本的な実装例

type ErrorCode int

const (
    BadRequest ErrorCode = iota + 1
    Required
    InvalidChars
    InternalError
)

var messageMap = map[ErrorCode]string{
    BadRequest: "Bad Request error",
    Required:   "%sを入力してください",
    // ... 続く
}

func (e ErrorCode) Message() string {
    if msg, ok := messageMap[e]; ok {
        return msg
    }
    return "Unknown Error Msg"
}

パラメータをつけた実装例

func (e ErrorCode) FormatMessage(args ...interface{}) string {
    template := e.Message()
    return fmt.Sprintf(template, args...)
}

msg := Required.FormatMessage("ユーザー名")
// 出力: ユーザー名を入力してください

▶︎ こちらで試せます

まとめ

GoでEnum的な構造を実現する際は、要件に応じて使い分けましょう。

  • パターン1
    • シンプルで高速な文字列変換が必要な場合
  • パターン2
    動的なメッセージ生成や複雑なメタデータ管理が必要な場合

基本的にはパターン1をベースにし、複雑な関連データが必要になった段階でパターン2を検討するのが、Goらしいのかなと思っています。