Вызов реализации протокола по умолчанию из обычного метода


Я интересно, если это возможно, чтобы достичь такой вещи.
У меня есть площадка, как это:

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 нужно все, что находится в реализации по умолчанию плюс дополнительные вещи?
Это как-то похоже на вызов super. методы class Эс для того чтобы выполнить требование снабжать каждое свойство ЕТК. но я не вижу возможности добиться того же с structs.

4 58

4 ответа:

Я не знаю, если вы все еще ищете ответ на этот вопрос, но способ сделать это-удалить функцию из определения протокола, приведите свой объект к 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")
    }
}

Спасибо за пост! Если вы поместите определение функции в протокол, то при приведении объекта в качестве протокола он видит только версию объекта функции, и поскольку вы вызываете его внутри себя, вы получаете новый адрес 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

В случае, если ваш протокол associatedType или Self требования, то бросок не будет работать. Чтобы обойти это, создайте" теневую " реализацию по умолчанию, которую может вызвать как обычная реализация по умолчанию, так и соответствующий тип.

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