[英]Why does a mutating method in a Swift protocol infinitely recurse unless only an extension method?
我在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?
为什么cm()
会一次又一次地调用自己?
通过在第二个示例中进行更改,通过在协议定义中包含m
,指示Swift使用动态分派。 因此,当您调用pm()
,它会动态确定对象是否已覆盖方法的默认实现。 在这个特定的例子中,这导致该方法以递归方式调用自身。
但是在第一个例子中,如果方法不是协议定义的一部分,Swift将使用静态分派,并且因为p
是P
类型,它将在P
调用m
实现。
举例来说,考虑方法不在协议定义的一部分(因此不在“协议见证表”中):
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
变量是P
类型,但它将动态确定底层类型Foo
是否覆盖了该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态与静态调度的更多信息,请参阅WWDC 2016视频了解Swift性能 。
通过在协议中声明m
并在类中提供实现,它会覆盖默认实现。
但是在第一个示例中,当您将类转换为协议时,它将调用协议的默认实现,因为类的实现是自己的,而不是编写任何协议的方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.