为什么在斯威夫特协议的不同诱变方法无限递归除非只有一个扩展方法?

问题描述 投票:3回答:2

我在SR-142 on bugs.swift.org跨越下面的代码来了。

如果协议有一个扩展方法多数民众赞成突变,一个类的实例可以调用函数变异没有任何问题。

// 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()保持连连自称?

swift protocols
2个回答
3
投票

在第二个例子中的变化,通过包括在协议定义的m,指示雨燕采用动态调度。所以,当你调用p.m(),它动态地确定对象是否已覆盖的方法的默认实现。在这个特殊的例子,这导致该方法递归调用自身。

但是在第一示例中,在不存在协议定义的所述方法的部分的,SWIFT将采用静态调度,并且因为p是类型P的,它将调用在mP实现。


通过示例的方式,考虑其中的方法没有(在“协议证人表”,因此不)协议定义的一部分:

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变量的类型P的,它会动态地确定是否底层类型,Foo,已重写该方法:

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

有关动态VS静态调度的更多信息,请参阅WWDC 2016的视频Understanding Swift Performance


1
投票

通过该协议,宣布m和你们班提供实现,它在写默认的实现。

但在第一个例子,当你投你的类作为协议,它会调用协议的默认实现,因为类的实现是它自己的,而不是在写任何协议的方法

© www.soinside.com 2019 - 2024. All rights reserved.