我在SR-142 on bugs.swift.org跨越下面的代码来了。
如果协议有一个扩展方法多数民众赞成突变,一个类的实例可以调用函数变异没有任何问题。
// 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
,指示雨燕采用动态调度。所以,当你调用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
,已重写该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态VS静态调度的更多信息,请参阅WWDC 2016的视频Understanding Swift Performance。
通过该协议,宣布m
和你们班提供实现,它在写默认的实现。
但在第一个例子,当你投你的类作为协议,它会调用协议的默认实现,因为类的实现是它自己的,而不是在写任何协议的方法