2017-12-01 9 views
4

同じプロトコルに準拠している私のプロジェクトにはいくつかの異なる列挙型があります。プロトコルのcompareEnumTypeメソッドは、関連付けられた値を無視して列挙型のケースを比較します。ここに遊び場から私のコードです:私は2つの以上の列挙型を持っている私の実際のプロジェクトで関連する値を無視したSwift Enum型の比較 - 一般的な実装

protocol EquatableEnumType { 
    static func compareEnumType(lhs: Self, rhs: Self) -> Bool 
} 

enum MyEnum: EquatableEnumType { 
    case A(Int) 
    case B 

    static func compareEnumType(lhs: MyEnum, rhs: MyEnum) -> Bool { 
     switch (lhs, rhs) { 
     case (.A, .A): return true 
     case (.B, .B): return true 
     default: return false 
     } 
    } 
} 

enum MyEnum2: EquatableEnumType { 
    case X(String) 
    case Y 

    static func compareEnumType(lhs: MyEnum2, rhs: MyEnum2) -> Bool { 
     switch (lhs, rhs) { 
     case (.X, .X): return true 
     case (.Y, .Y): return true 
     default: return false 
     } 
    } 
} 

let a = MyEnum.A(5) 
let a1 = MyEnum.A(3) 
if MyEnum.compareEnumType(lhs: a, rhs: a1) { 
    print("equal") // -> true, prints "equal" 
} 

let x = MyEnum2.X("table") 
let x1 = MyEnum2.X("chair") 
if MyEnum2.compareEnumType(lhs: x, rhs: x1) { 
    print("equal2") // -> true, prints "equal2" 
} 

は、それらのそれぞれのために私はcompareEnumType機能の同様の実装を持っている必要があります。

質問はEquatableEnumTypeプロトコルに準拠するすべての列挙型で動作するcompareEnumTypeの汎用実装を持つことが可能ですか?

私はこのようなプロトコル拡張でデフォルトの実装を書き込もうとしました:

extension EquatableEnumType { 
    static func compareEnumType(lhs: Self, rhs: Self) -> Bool { 
     // how to implement??? 
    } 
} 

しかし、私は実装にこだわっています。 lhsrhsに含まれる値にアクセスする方法はありません。誰か助けてくれますか?

+0

クラス型アイデンティティ以外のEquatable型の非価値的な側面を公開することは避け、公開されているものは明示的に文書で指摘する必要があります。これは非常に悪い考えであり、あなたはそれを避けるためにタイプを再設計するべきです。これを行うことに決めた場合、必要なツールはSwiftGenです。 –

+0

列挙型に等価性に関係のないプライベート情報(キャッシュなど)がある場合は、代わりにここでクラスまたは構造体を使用してください。列挙型はその問題にはあまり適していません。 (enumベースのソリューションは、プロトコル+構造体ベースの同等のものに変換することができます。その逆もあります。メンテナンスのトレードオフは異なりますが、それらはデュアルであるため、ロジックは常に実装できます)。 –

+2

@RobNapier I don ==の意味や実装を変更したい。私はそれが関連する値を考慮に入れることを知っており、それは正しいです。私の議定書では、関連する値を無視して、列挙型のケースのみを比較したいと考えています。私は==を使ってみましたが、それは私のためにはうまくいきません(これは正しい)。私は、一般的な方法で関連付けられた値を無視して列挙型のケースを比較する方法のための別のソリューションを探しています。 – Anastasia

答えて

0

私はあなたがこれを自動生成できるとは思わないので、ここでは拡張機能を使用しています。 enum CompareEnumMethodを作成して、関連するvaluesを比較するか、typeのみを比較するかを教えてください。このenumをパラメータとして持つ新しい関数compareEnumを作成します。次に、==(lhs:,rhs:)の拡張子を作成し、.valueを使用し、compareEnumTypeの場合は.typeを使用します。各列挙型ではcompareEnumメソッドのみを実装する必要があります。これは、「代替-任意の均等比較する2つのインスタンスがその値に依存して任意のコードに交換可能に使用することができる。代替性を維持するために、==演算子を考慮に入れなければならない意味 `Equatable`、の意味に違反

enum CompareEnumMethod { 
    case type, value 
} 

protocol EquatableEnumType: Equatable { 
    static func compareEnumType(lhs: Self, rhs: Self) -> Bool 
    static func compareEnum(lhs: Self, rhs: Self, method: CompareEnumMethod) -> Bool 
} 

extension EquatableEnumType { 
    static func compareEnumType(lhs: Self, rhs: Self) -> Bool { 
     return Self.compareEnum(lhs: lhs, rhs: rhs, method: .type) 
    } 

    static func ==(lhs: Self, rhs: Self) -> Bool { 
     return Self.compareEnum(lhs: lhs, rhs: rhs, method: .value) 
    } 
} 

enum MyEnum: EquatableEnumType { 
    case A(Int) 
    case B 

    static func compareEnum(lhs: MyEnum, rhs: MyEnum, method: CompareEnumMethod) -> Bool { 
     switch (lhs, rhs, method) { 
     case let (.A(lhsA), .A(rhsA), .value): 
      return lhsA == rhsA 
     case (.A, .A, .type), 
      (.B, .B, _): 
      return true 
     default: 
      return false 
     } 
    } 
} 

let a0 = MyEnum.A(5) 
let a1 = MyEnum.A(3) 
let b0 = MyEnum.B 
print(MyEnum.compareEnumType(lhs: a0, rhs: a1)) //true 
print(a0 == a1) //false 
print(MyEnum.compareEnumType(lhs: a0, rhs: b0)) //false 
+0

ありがとうございました!しかし、このようにcompareEnum()は各enum(MyEnum2のコードスニペットなど)ごとに異なる実装を持つ必要があります。それは私が避けようとしていることです。EquatableEnumTypeに準拠するすべての列挙型に対して1つの実装をしたいと思います。 – Anastasia

関連する問題