関連する値を持つ Swift 列挙型の等価性をテストする方法 質問する

関連する値を持つ Swift 列挙型の等価性をテストする方法 質問する

2 つの Swift 列挙値の等価性をテストしたいと思います。例:

enum SimpleToken {
    case Name(String)
    case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)

ただし、コンパイラは等式をコンパイルしません。

error: could not find an overload for '==' that accepts the supplied arguments
    XCTAssert(t1 == t2)
    ^~~~~~~~~~~~~~~~~~~

等価演算子のオーバーロードを独自に定義する必要がありますか? Scala や Ocaml と同様に、Swift コンパイラーが自動的に処理してくれることを期待していました。

ベストアンサー1

Swift 4.1以降

@jedwidz が親切に指摘してくれたように、Swift 4.1 以降 ( SE-0185のため)、Swift は関連付けられた値を持つ列挙型の合成Equatableともサポートします。Hashable

したがって、Swift 4.1 以降を使用している場合は、次のようにすると、XCTAssert(t1 == t2)機能するために必要なメソッドが自動的に合成されます。重要なのは、Equatableプロトコルを列挙型に追加することです。

enum SimpleToken: Equatable {
    case name(String)
    case number(Int)
}
let t1 = SimpleToken.number(123)
let t2 = SimpleToken.number(123)

Swift 4.1以前

他の人が指摘しているように、Swift は必要な等価演算子を自動的に合成しません。ただし、よりクリーンな (私見) 実装を提案します。

enum SimpleToken: Equatable {
    case name(String)
    case number(Int)
}

public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
    switch (lhs, rhs) {
    case let (.name(a),   .name(b)),
         let (.number(a), .number(b)):
      return a == b
    default:
      return false
    }
}

これは理想からは程遠く、繰り返しが多くありますが、少なくとも内部に if ステートメントを含むネストされたスイッチを実行する必要はありません。

おすすめ記事