SwiftのenumはC++のenum classよりsum typeとして見ると分かりやすい

Swiftの enum は、C++の enum class だけを想像すると少し足りません。

単なる名前付き整数というより、状態の種類と値をまとめて表せるsum typeとして見ると理解しやすいです。

公式でも、Swiftのenumerationはcaseを定義し、caseごとにassociated valueを持てるものとして説明されています。

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations/

普通のenum

まずは単純なenumです。

enum Direction {
    case up
    case down
    case left
    case right
}

使う側はこうです。

let direction: Direction = .up

このあたりはC++の enum class に近いです。

enum class Direction {
    up,
    down,
    left,
    right,
};

associated values

Swiftらしいのはここからです。

enum LoadState {
    case idle
    case loading
    case loaded([String])
    case failed(Error)
}

loaded は配列を持ち、failedError を持ちます。

let state = LoadState.loaded(["A", "B"])

C++で近いことをするなら、std::variant に寄せる感覚です。

using LoadState = std::variant<Idle, Loading, Loaded, Failed>;

Swiftのenumは、caseと値の組み合わせを言語機能として扱えます。

switchで取り出す

associated valueは switch で取り出します。

switch state {
case .idle:
    print("idle")
case .loading:
    print("loading")
case .loaded(let items):
    print(items)
case .failed(let error):
    print(error)
}

Swiftの switch は網羅性チェックがあります。

caseを追加すると、対応していないswitchでコンパイルエラーになります。

このチェックはかなり助かります。状態が増えたときに、表示や処理を直し忘れにくいです。

Optionalもenumとして見られる

Swiftの Optional も、だいたいenumとして考えられます。

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

実際の定義は標準ライブラリ側ですが、考え方としてはこうです。

String? は「Stringがある」か「ない」かのenumだと思うと、C++の std::optional<T> にかなり近いです。

Optionalについては SwiftのOptionalをC++のnullptrやstd::optionalと比べて整理する に分けています。

まとめ

Swiftのenumは、C++の enum class より広いものとして見るとよいです。

  • 単純なcase列挙もできる
  • caseごとに値を持てる
  • switch で値を取り出せる
  • 網羅性チェックが効く
  • std::variantstd::optional に近い使い方もある

状態管理を書くときは、まずenumで表せないかを見ると、Swiftでは自然な形になりやすいです。

関連記事

参考