我在bug.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()
不断不断地自我称呼?
通过第二个示例中的更改,通过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实现”,因为尽管foo
变量是type P
,但它将动态确定基础类型Foo
是否覆盖了该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态与静态调度的更多信息,请参阅WWDC 2016视频“了解Swift性能”。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句