私は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")
}
}
なぜならfoo
でP
参照及びため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]
コメントを追加