web-dev-qa-db-ja.com

クラス階層にEquatableプロトコルを適切に実装するにはどうすればよいですか?

==演算子(Equatableから)を基本クラスに実装しようとしています。そのサブクラスはSwift 3。すべてのクラスのみが使用されます。 in Swiftなので、NSObjectまたはNSCopyingプロトコルを使用したくありません。

私は基本クラスとサブクラスから始めました:

class Base {
    var x : Int
}

class Subclass : Base {
    var y : String
}

ここで、Equatable==演算子をBaseに追加したいと思いました。簡単そうです。ドキュメントから==オペレーター署名をコピーします。

class Base : Equatable {
    var x : Int

    static func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

ここまでは順調ですね。サブクラスについて:

class Subclass : Base {
    static override func == (lhs: Base, rhs: Base) -> Bool {
        return true
    }
}

しかし、これはエラーになります:

演算子関数は「最終的な」演算子関数をオーバーライドします

OK。いくつかの調査(まだ学習中Swift 3)の後、typeメソッドをオーバーライドできることを示すためにstaticclassに置き換えることができることを学びました。

そこで、staticclassBaseに変更しようとしています。

class Base : Equatable {
    var x : Int

    class func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

しかし、それは新しいエラーになります:

非最終クラス 'Base'で宣言された演算子 '=='は 'final'でなければなりません

うーん。これは、本来よりもはるかに複雑です。

Equatableプロトコルと==演算子を基本クラスとサブクラスに適切に実装するにはどうすればよいですか?

13
rmaddy

たくさんの研究と試行錯誤の末、私はついに実用的な解決策を思いつきました。最初のステップは、==演算子をクラス内からグローバルスコープに移動することでした。これにより、staticfinalに関するエラーが修正されました。

基本クラスの場合、これは次のようになります。

func == (lhs: Base, rhs: Base) -> Bool {
    return lhs.x == rhs.x
}

class Base : Equatable {
    var x : Int
}

そしてサブクラスの場合:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
    return true
}

class Subclass : Base {
    var y : String
}

残っているのは、サブクラスの==演算子から基本クラスの==演算子を呼び出す方法を理解することだけです。これは私を最終的な解決策に導きました:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
    if lhs.y == rhs.y {
        if lhs as Base == rhs as Base {
            return true
        }
    }

    return false
}

その最初のifステートメントは、基本クラスの==演算子の呼び出しになります。


最終的な解決策:

Base.Swift:

func == (lhs: Base, rhs: Base) -> Bool {
    return lhs.x == rhs.x
}

class Base : Equatable {
    var x : Int
}

Subclass.Swift:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
    if lhs.y == rhs.y {
        if lhs as Base == rhs as Base {
            return true
        }
    }

    return false
}

class Subclass : Base {
    var y : String
}
13
rmaddy

他の答えに続いて、私はこれを思いついた:

class Base : Equatable {
    var x : Int
    static func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

class Subclass : Base {
    var y : String
    static func == (lhs: Subclass, rhs: Subclass) -> Bool {
        return lhs.y == rhs.y && (lhs as Base) == (rhs as Base)
    }
}
1
Vello Vaherpuu

rmaddyの答え に続いて、私は平等をテストするためのガードアプローチを思いつきました:

Base.Swift


static func ==(lhs: Base, rhs: Base) -> Bool {
    // ensure class properties match
    guard lhs.x == rhs.x else {
        return false
    }

    return true

}

Subclass.Swift


static func ==(lhs: Subclass, rhs: Subclass) -> Bool {
    // ensure base class properties match
    guard lhs as Base == rhs as Base else {
        return false
    }

    // ensure class properties match
    guard lhs.y == rhs.y else {
        return false
    }

    return true
}

`` `

0
Toland Hon