繁体   English   中英

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

[英]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将使用静态分派,并且因为pP类型,它将在P调用m实现。


举例来说,考虑方法不在协议定义的一部分(因此不在“协议见证表”中):

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变量是P类型,但它将动态确定底层类型Foo是否覆盖了该方法:

let foo: P = Foo()
foo.method()              // Foo implementation

有关动态与静态调度的更多信息,请参阅WWDC 2016视频了解Swift性能

通过在协议中声明m并在类中提供实现,它会覆盖默认实现。

但是在第一个示例中,当您将类转换为协议时,它将调用协议的默认实现,因为类的实现是自己的,而不是编写任何协议的方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM