3

structSwiftにかなり大きなものがあると仮定しましょう:

struct SuperStruct {
    var field1: Int = 0
    var field2: String = ""
    // lots of lines...
    var field512: Float = 0.0
}

..そして、Equatableプロトコルを実装する必要があります:

extension SuperStruct: Equatable {
}

func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {
    return
        lhs.field1 == rhs.field1 &&
        lhs.field2 == rhs.field2 &&
        // lots of lines...
        lhs.field512 == rhs.field512
}

...そして、ばかげたコードを何行も書く必要があります。私たちのためにそれを「行う」ようにコンパイラに「依頼する」方法はありますか?

4

4 に答える 4

5

次の回答は、考えられる解決策の 1 つを示しています。おそらく推奨されるものではありません(ただし、この質問の将来の読者にとってはおそらく興味深いでしょう)。


幾分制限された数の異なるタイプにすべて属する多数のプロパティがある場合、構造体インスタンスの を使用Mirrorして、構造体のプロパティを反復処理できます。プロパティが既知のさまざまなタイプへの変換を試みるたびに。

次の WWDC 2015 セッション (Leo Dabus に感謝します!) を見た後、以前の回答を編集しました (かなりすっきりしていると思います)。

Mirrorこのソリューションを利用するための、プロトコル指向ではない代替アプローチを示すため、最初の回答もこの回答の最後に残します。

Mirror& プロトコル指向のソリューション:

/* Let a heterogeneous protocol act as "pseudo-generic" type
   for the different (property) types in 'SuperStruct'         */
protocol MyGenericType {
    func isEqualTo(other: MyGenericType) -> Bool
}
extension MyGenericType where Self : Equatable {
    func isEqualTo(other: MyGenericType) -> Bool {
        if let o = other as? Self { return self == o }
        return false
    }
}

/* Extend types that appear in 'SuperStruct' to MyGenericType  */
extension Int : MyGenericType {}
extension String : MyGenericType {}
extension Float : MyGenericType {}
    // ...

/* Finally, 'SuperStruct' conformance to Equatable */
func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {

    let mLhs = Mirror(reflecting: lhs).children.filter { $0.label != nil }
    let mRhs = Mirror(reflecting: rhs).children.filter { $0.label != nil }

    for i in 0..<mLhs.count {
        guard let valLhs = mLhs[i].value as? MyGenericType, valRhs = mRhs[i].value as? MyGenericType else {
            print("Invalid: Properties 'lhs.\(mLhs[i].label!)' and/or 'rhs.\(mRhs[i].label!)' are not of 'MyGenericType' types.")
            return false
        }
        if !valLhs.isEqualTo(valRhs) {
            return false
        }
    }
    return true
}

使用例:

/* Example */
var a = SuperStruct()
var b = SuperStruct()
a == b // true
a.field1 = 2
a == b // false
b.field1 = 2
b.field2 = "Foo"
a.field2 = "Foo"
a == b // true

以前のMirror解決策:

/* 'SuperStruct' conformance to Equatable */
func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {

    let mLhs = Mirror(reflecting: lhs).children.filter { $0.label != nil }
    let mRhs = Mirror(reflecting: rhs).children.filter { $0.label != nil }

    for i in 0..<mLhs.count {
        switch mLhs[i].value {
        case let valLhs as Int:
            guard let valRhs = mRhs[i].value as? Int where valRhs == valLhs else {
                return false
            }
        case let valLhs as String:
            guard let valRhs = mRhs[i].value as? String where valRhs == valLhs else {
                return false
            }
        case let valLhs as Float:
            guard let valRhs = mRhs[i].value as? Float where valRhs == valLhs else {
                return false
            }
            /* ... extend with one case for each type
            that appear in 'SuperStruct'  */
        case _ : return false
        }
    }
    return true
}

使用例:

/* Example */
var a = SuperStruct()
var b = SuperStruct()
a == b // true
a.field1 = 2
a == b // false
b.field1 = 2
b.field2 = "Foo"
a.field2 = "Foo"
a == b // true
于 2016-01-26T21:47:42.673 に答える