30

グローバル スコープでメソッドを宣言する方法について言及しているこのSwift Equatable Protocolの質問に対する回答を見てきました。==

を採用しない場合でも、2 つの型が等しいかどうかをテストするようにEquatable宣言できます。==

// extension Foo: Equatable {}

func ==(lhs: Foo, rhs: Foo) -> Bool {
    return lhs.bar == rhs.bar
}

struct Foo {
    let bar:Int
}

その実装をグローバル スコープで宣言する必要があるという事実は、たとえ採用されたとしても、それがプロトコルに付随しており、プロトコルとは異なるように思わせます。Equatable

プロトコルは、Equatable型がプロトコルの必要なメソッドを実装したことを (私たちと) コンパイラに安全に知らせるだけの構文糖衣以上のものであるでしょうか?

プロトコルであっても、オペレーターの実装をグローバルに宣言する必要があるのはなぜですか? これは、オペレーターの派遣方法が異なるためですか?

4

5 に答える 5

22

アップデート

Xcode 8 ベータ 4 リリース ノートから:

演算子は、型またはその拡張内で定義できます。例えば:

struct Foo: Equatable {
    let value: Int
    static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.value == rhs.value
    }
}

staticこのような演算子は、 として(または、クラス内で)宣言する必要がありclass final、対応するグローバル演算子と同じシグネチャを持っている必要があります。この変更の一環として、プロトコルで宣言されたオペレーター要件も明示的に宣言する必要がありますstatic

protocol Equatable {
    static func ==(lhs: Self, rhs: Self) -> Bool
}

オリジナル

これは最近、swift-evolution リストで議論されました (2016-01-31 から 2016-02-09 まで)。構造体またはクラスのスコープで演算子を宣言することに関して、クリス・ラトナーが言ったことは次のとおりです。

はい、これは一般的に望ましい機能です (少なくとも対称演算子の場合)。これは、クラス宣言内で演算子を動的にディスパッチするのにも最適です。ただし、名前検索がこれでどのように機能するかを明確にする確固たる提案があるとは思いません。

そして後で(Haravikkに返信):

名前検索の問題とは何ですか? Foo == Foo の演算子が複数の場所に存在する場合のことですか?

はい。名前検索では、シャドーイングと無効な複数定義ルールを定義する、明確に定義された検索順序が必要です。

つまり、特定のクラス/構造体内の演算子の実装をとにかくグローバルに定義されているものとして扱い、同じ署名が複数回宣言されている場合はエラーをスローします。

オペレーターのインスタンスを定義できるようにするには複数のモジュールが必要であり、拡張機能にはオペレーターが必要であり、他のメンバーと同様に機能するには遡及適合が必要です。

于 2016-02-10T20:34:56.823 に答える
7

ドキュメントからの説明

演算子関数は、オーバーロードされる演算子と一致する関数名を持つグローバル関数として定義されます。

関数は、ターゲット クラスまたは構造体のメソッドとしてではなく、グローバルに定義されるため、ターゲット クラスまたは構造体の既存のインスタンス間で中置演算子として使用できます。

Vector2D引用の具象構造体 ( ) の名前を、一般的な式のターゲット クラスまたは構造体に置き換えました。

于 2016-02-10T20:26:13.560 に答える