拡張メソッドだけでない限り、Swiftプロトコルのミューテーションメソッドが無限に繰り返されるのはなぜですか?

lochiwei

私はbugs.swift.orgのSR-142で次のコードに出くわしました

プロトコルに変更する拡張メソッドがある場合、クラスインスタンスは問題なく変更関数を呼び出すことができます。

// protocol definition
protocol P { }

extension P {
    mutating func m() { }
}

// class conforming to P
class C : P {
    // redeclare m() without the mutating qualifier
    func m() {
        // call protocol's default implementation
        var p: P = self 
        p.m()
    }
}

let c = C()
c.m()

プロトコル宣言にメソッドを追加するために小さな変更を加えた場合:

protocol P {
  mutating func m()  // This is what I added.
}

extension P { 
  mutating func m() { } 
}

class C : P { 
  func m() { 
    var p: P = self 
    p.m() 
  }
}

let c = C() 
c.m()         // This one is calling itself indefinitely; why?

なぜ何度も何度もc.m()自分自身を呼び出し続けるのですか?

ロブ

2番目の例での変更ではm、プロトコル定義にを含めることで、動的ディスパッチを採用するようにSwiftに指示します。したがって、を呼び出すとp.m()、オブジェクトがメソッドのデフォルトの実装をオーバーライドしたかどうかが動的に判別されます。この特定の例では、その結果、メソッドはそれ自体を再帰的に呼び出します。

ただし、最初の例では、プロトコル定義の一部であるメソッドがない場合、Swiftは静的ディスパッチを使用し、pタイプがであるためP、のm実装を呼び出しますP


例として、メソッドがプロトコル定義の一部ではない(したがって、「プロトコル監視テーブル」にない)場合を考えてみます。

protocol P {
    // func method()
}

extension P {
    func method() {
        print("Protocol default implementation")
    }
}

struct Foo: P {
    func method() {
        print(“Foo implementation")
    }
}

なぜならfooP参照及びためmethodの一部ではなくP、定義その除外methodプロトコル証人テーブルから静的ディスパッチを採用しています。その結果、以下は「プロトコルのデフォルト実装」を出力します。

let foo: P = Foo()
foo.method()              // Protocol default implementation

ただし、プロトコルを変更してこのメ​​ソッドを明示的に含めると、他のすべては同じままmethodで、プロトコル監視テーブルに含まれます。

protocol P {
    func method()
}

次に、foo変数は型ですがP、基になる型Fooがそのメソッドをオーバーライドしたかどうかを動的に判別するため、以下は「Foo実装」を出力します

let foo: P = Foo()
foo.method()              // Foo implementation

動的ディスパッチと静的ディスパッチの詳細については、WWDC2016のビデオ「Swiftパフォーマンスについて」を参照してください

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ