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



我想知道是否有可能实现这样的事情。
我有一个这样的游乐场:

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()

我可以在extension中提供默认实现,但如果Bar需要默认实现中的所有内容加上额外的东西怎么办?
这在某种程度上类似于在class中调用super.方法来满足实现每个属性等的要求,但我认为没有可能实现与structs相同。

我不知道你是否还在寻找答案,但要做到这一点的方法是从协议定义中删除函数,将对象转换为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"

由于某种原因,只有当函数没有作为协议的一部分声明,而是在协议的扩展中定义时,它才有效。图。

那么,您可以创建一个符合协议的嵌套类型,实例化它,并调用该类型的方法(您无法访问类型的数据,因为协议扩展内的实现无论如何都无法引用它,这无关紧要)。但我认为这不是一个优雅的解决方案。

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

您觉得这样解决这个问题怎么样?

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()

谢谢!如果你把函数定义放在协议中,那么当对象被强制转换为协议时,它只会看到对象的函数版本,因为你在自己内部调用它,所以你会得到Apple的新地址…

我试过这样一个版本:

import UIKit
protocol MyProc
{
}
protocol MyFuncProc
{
    func myFunc()
}
extension MyProc
{
    func myFunc()
    {
        print("Extension Version")
    }
}
struct MyStruct: MyProc, MyFuncProc
{
    func myFunc()
    {
        print("Structure Version")
        (self as MyProc).myFunc()
    }
}
(MyStruct() as MyFuncProc).myFunc()

输出如下:

Structure Version
Extension Version

如果您的协议有associatedTypeSelf要求,则强制转换将不起作用。为了解决这个问题,创建一个"影子"默认实现,常规默认实现和符合类型都可以调用。

protocol Foo { 
    associatedType Bar
}
extension Foo {
    func testPrint() {
        defaultTestPrint()
    }
}
fileprivate extension Foo { // keep this as private as possible
    func defaultTestPrint() {
        // default implementation
    }
}
struct Bar: Foo {
    func testPrint() {
        // specialized implementation
        defaultTestPrint()
    }
}

我想到了一个解决办法。

当你在扩展中有一个默认实现时,当你将协议实现到另一个类/结构时,如果你实现该方法,你将失去这个默认实现。这就是设计,这就是协议的工作方式

解决方案
  • 创建你的协议的默认实现,并使其成为你的协议的属性。
  • 当你在一个类中实现这个协议时,为你的默认实现提供一个getter
  • 需要时调用默认实现。


protocol Foo {
    var defaultImplementation: DefaultImpl? { get }
    func testPrint()
}
extension Foo {
    // Add default implementation
    var defaultImplementation: DefaultImpl? {
        get {
            return nil
        }
    }
}
struct DefaultImpl: Foo {
    func testPrint() {
        print("Foo")
    }
}

extension Foo {
    
    func testPrint() {
        defaultImplementation?.testPrint()
    }
}
struct Bar: Foo {
    
    var defaultImplementation: DefaultImpl? {
        get { return DefaultImpl() }
    }
    func testPrint() {
        if someCondition {
            defaultImplementation?.testPrint() // Prints "Foo"
        }
    }
}
struct Baz: Foo {
    func testPrint() {
        print("Baz")
    }
}

let bar = Bar()
bar.testPrint() // prints "Foo"
let baz = Baz()
baz.testPrint() // prints "Baz"

缺点

在实现该协议的结构/类中丢失了所需的实现错误

最新更新