1. ホーム
  2. スイフト

[解決済み】Swiftの列挙型と関連する値の等質性をテストする方法

2022-04-10 05:11:29

質問

2つのSwift enumの値が等しいかどうかをテストしたい。 例えば

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 コンパイラが自動的にそれを処理することを期待していました。

どのように解決するのですか?

Swift 4.1+

として JEDWIDZ は、Swift 4.1以降、(そのため、) SE-0185 を合成することもサポートしています。 EquatableHashable は、関連する値を持つ列挙型のためのものです。

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 は必要な等式演算子を自動的に合成しません。しかし、私はよりクリーンな(IMHO)実装を提案させてください。

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ステートメントを内部に含むネストされたスイッチを作る必要はありません。