从常规方法调用协议默认实现

coj*_*joj 75 oop protocols swift swift2

我想知道是否有可能实现这样的目标.
我有一个像这样的游乐场:

protocol Foo {
    func testPrint()
}

extension Foo {
    func testPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        // Calling self or super go call default implementation
        self.testPrint()
        print("Call from struct")
    }
}


let sth = Bar()
sth.testPrint()
Run Code Online (Sandbox Code Playgroud)

我可以提供一个默认实现,extension但如果Bar需要默认实现中的所有内容以及其他内容,该怎么办?
它在某种程度上类似于调用es中的super.方法class来满足实现每个属性等的要求,但我认为没有可能实现相同的structs.

Aar*_*sen 86

我不知道你是否还在寻找答案,但是这样做的方法是从协议定义中删除函数,将对象转换为Foo然后调用它上面的方法:

protocol Foo { 
    // func testPrint() <- comment this out or remove it
}

extension Foo {
    func testPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        print("Call from struct")
        (self as Foo).testPrint() // <- cast to Foo and you'll get the  default
                                  //    function defined in the extension
    }
}

Bar().testPrint()

// Output:    "Call from struct"
//            "Protocol extension call"
Run Code Online (Sandbox Code Playgroud)

由于某种原因,只有在函数未被声明为协议的一部分时才会起作用,但是在协议的扩展中定义了该函数.去搞清楚.但它确实有效.

  • 这实际上彻底改变了协议+扩展的语义.如果将声明保留在协议之外,则在符合协议的类型上调用函数时将获得_static_ dispatch - 这就是您可以从扩展中强制转换实现的原因.如果将声明添加到协议,则对函数的调用将为_dynamically_ dispatched. (13认同)
  • 对我来说这看起来像一个错误,这不应该只通过转换相同的实例来获得不同的方法实现. (5认同)
  • 这不会导致无限循环吗? (4认同)
  • @RomanSausarnes 我不知道你为什么不同意。您可以从子类的**内部**访问超级的实现 - 没关系。如果您将子类实例向下转换为超类并调用重写方法,您仍然可以获得子类实现。但是,您可以在 `Bar` 实现之外调用 `(self as Foo).testPrint()`,对吗?因此,您可以从子类实现的**外部**访问超类(在这种情况下是默认协议扩展imp)实现,这就是我发现的错误。在这种情况下,“Bar”演示了“Foo”的行为,这是错误的。 (2认同)
  • 只有当`Foo`协议不从任何其他协议继承时,这才有效. (2认同)
  • 我尝试过这种方式,并且进入了无限循环。 (2认同)

小智 9

您对这种解决此问题的方式有何看法?

protocol Foo {
    func testPrint()
}

extension Foo {
    func testPrint() {
        defaultTestPrint()
    }

    func defaultTestPrint() {
        print("Protocol extension call")
    }
}

struct Bar: Foo {
    func testPrint() {
        // Calling self or super go call default implementation
        defaultTestPrint()
        print("Call from struct")
    }
}


let sth = Bar()
sth.testPrint()
Run Code Online (Sandbox Code Playgroud)


Tho*_*rer 8

好吧,你可以创建一个符合协议的嵌套类型,实例化它,并在那个上调用方法(无论你无法访问类型的数据都无关紧要,因为协议扩展中的实现无论如何都无法引用它).但这不是我称之为优雅的解决方案.

struct Bar: Foo {
    func testPrint() {
        // Calling default implementation
        struct Dummy : Foo {}
        let dummy = Dummy()
        dummy.testPrint()
        print("Call from struct")
    }
}
Run Code Online (Sandbox Code Playgroud)