为什么 Swift 协议中的变异方法会无限递归,除非只有扩展方法?
Why does a mutating method in a Swift protocol infinitely recurse unless only an extension method?
我在 SR-142 on bugs.swift.org 中遇到了以下代码。
如果协议有一个正在变异的扩展方法,class 实例可以毫无问题地调用变异函数。
// 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
并在您的 class 中提供实现,它覆盖了默认实现。
但是在第一个示例中,当您将 class 转换为协议时,它将调用协议的默认实现,因为 class 的实现是它自己的,并且不会覆盖协议的任何方法
在第二个示例中,通过在协议定义中包含 m
,指示 Swift 使用动态调度。所以当你调用p.m()
时,它会动态判断对象是否重写了方法的默认实现。在此特定示例中,这导致方法递归调用自身。
但是在第一个例子中,在没有方法作为协议定义的一部分的情况下,Swift 将使用静态调度,并且因为 p
是 P
类型,它将在 P
.
中调用 m
实现
举例来说,考虑方法不是协议定义的一部分(因此不在“协议见证 table”中):
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
table 并采用静态调度。结果,以下将打印“协议默认实现”:
let foo: P = Foo()
foo.method() // Protocol default implementation
但是如果您更改协议以显式包含此方法,而其他一切保持不变,method
将包含在协议见证中 table:
protocol P {
func method()
}
然后下面会打印“Foo implementation”,因为虽然foo
变量是P
类型,它会动态判断底层类型Foo
是否有覆盖该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态与静态调度的更多信息,请参阅 WWDC 2016 视频 Understanding Swift Performance。
我在 SR-142 on bugs.swift.org 中遇到了以下代码。
如果协议有一个正在变异的扩展方法,class 实例可以毫无问题地调用变异函数。
// 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
并在您的 class 中提供实现,它覆盖了默认实现。
但是在第一个示例中,当您将 class 转换为协议时,它将调用协议的默认实现,因为 class 的实现是它自己的,并且不会覆盖协议的任何方法
在第二个示例中,通过在协议定义中包含 m
,指示 Swift 使用动态调度。所以当你调用p.m()
时,它会动态判断对象是否重写了方法的默认实现。在此特定示例中,这导致方法递归调用自身。
但是在第一个例子中,在没有方法作为协议定义的一部分的情况下,Swift 将使用静态调度,并且因为 p
是 P
类型,它将在 P
.
m
实现
举例来说,考虑方法不是协议定义的一部分(因此不在“协议见证 table”中):
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
table 并采用静态调度。结果,以下将打印“协议默认实现”:
let foo: P = Foo()
foo.method() // Protocol default implementation
但是如果您更改协议以显式包含此方法,而其他一切保持不变,method
将包含在协议见证中 table:
protocol P {
func method()
}
然后下面会打印“Foo implementation”,因为虽然foo
变量是P
类型,它会动态判断底层类型Foo
是否有覆盖该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态与静态调度的更多信息,请参阅 WWDC 2016 视频 Understanding Swift Performance。