swift - 为什么 Swift 协议中的变异方法会无限递归,除非只有扩展方法?
问题描述
我在 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()
一遍又一遍地呼唤自己?
解决方案
随着您在第二个示例中的更改,通过m
在协议定义中包含 ,指示 Swift 使用动态调度。因此,当您调用 时p.m()
,它会动态确定对象是否覆盖了该方法的默认实现。在这个特定的示例中,这会导致该方法递归地调用自身。
但是在第一个例子中,在协议定义中没有方法的情况下,Swift 将使用静态调度,并且因为p
是 type P
,它会调用 in 中的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
因此,以下将打印“Protocol default implementation”:
let foo: P = Foo()
foo.method() // Protocol default implementation
但是,如果您更改协议以显式包含此方法,而其他所有内容保持不变,method
则将包含在协议见证表中:
protocol P {
func method()
}
然后下面将打印“Foo implementation”,因为尽管foo
变量是 type P
,但它将动态确定底层类型Foo
是否覆盖了该方法:
let foo: P = Foo()
foo.method() // Foo implementation
有关动态与静态调度的更多信息,请参阅 WWDC 2016 视频了解 Swift 性能。
推荐阅读
- sql - 当 SQL 中存在空值时,在 VBA 标签中显示标题“无结果”
- python - 如何使用 Python 中的键盘模块来监听按下的键的名称?
- angular - 澳大利亚电话号码验证不适用于 Angular
- python - 直方图难以正确显示推文天数
- javascript - React - 从“兄弟”组件调用函数
- html - 我可以通过额外的 css 进行这些更改吗?
- sql - 从 MS Access 中删除重复记录的查询
- javascript - 在数组中的每个当前字符串之间添加新字符串
- python-3.x - 当我们读取文件并打开它时会发生什么
- asp.net - 如何防止其他管理员用户解密 Web 配置