为什么Swift协议中的变异方法会无限递归,除非只有扩展方法?

lochiwei

在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")
    }
}

因为fooP引用,并且由于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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么此方法会导致无限循环?

为什么这种方法会陷入无限循环?

Swift 2.0中的协议扩展方法分派

覆盖现有的JavaScript Array.prototype方法会导致无限递归吗?

在Python中,为什么类方法会覆盖实例方法?

为什么添加onClick方法会在我的react render方法中导致无限循环

为什么(递归地)调用自身的成员方法没有进入无限循环?

为什么在此JavaScript示例中调用相同方法会有不同的输出?

为什么在C#中定义属性的两种方法会有不同的结果?

为什么“稍后”方法会导致“日期”范围内的无限范围?

为什么GET方法会在物件中传回物件

为什么我的方法会覆盖数组中的位置

为什么 append 方法会修改 python 类中的变量?

调用Swift协议扩展方法代替在子类中实现的方法

为什么Python使用属于外部包的方法会给出递归错误

为什么模拟后方法会执行?

为什么该方法会删除线?

为什么 readLong 方法会导致 EOFException?

如何在Swift中的协议扩展中覆盖实例方法?

使用错误委托中的方法进行Swift协议扩展仍然有效(?!)

为什么Iterator在Java中没有add方法而List Iterator在Java中只有add方法?

为什么在派生类中调用方法会调用基类方法?

为什么覆盖python中的getattr方法时没有无限循环

C#扩展方法比链式替换慢,除非处于紧密循环中。为什么?

协议扩展,变异功能

为什么带有便捷init()方法的Swift UIView子类在更新到Swift 3.0后会开始无限循环?

为什么带有参数的动词方法会阻塞另一个相同的路径?

为什么这两种获取布尔值的方法会有不同的结果?

为什么Spark Streaming中的多个print()方法会影响列表中的值?