programing

일반 메서드에서 프로토콜 기본 구현 호출

cafebook 2023. 9. 5. 20:46
반응형

일반 메서드에서 프로토콜 기본 구현 호출

저는 그런 일이 가능한지 궁금합니다.
다음과 같은 Playground가 있습니다.

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.의 방법.classes 모든 재산 등을 이행하는 요건을 충족시키지만, 저는 동일한 것을 달성할 가능성이 없다고 봅니다.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

당신의 프로토콜이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()
    }
}

저는 이것에 대한 해결책을 생각해냈습니다.

쟁점.

확장에 기본 구현이 있는 경우 다른 클래스/구조체에 프로토콜을 구현할 때 메소드를 구현하면 이 기본 구현이 손실됩니다.이것은 의도적으로, 이것이 프로토콜이 작동하는 방법입니다.

해결책

  • 프로토콜의 기본 구현을 만들어 프로토콜의 속성으로 만듭니다.
  • 그런 다음 클래스에서 이 프로토콜을 구현할 때 기본 구현을 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"


단점

이 프로토콜을 구현하는 구조/클래스에서 필요한 구현 오류가 손실됩니다.

언급URL : https://stackoverflow.com/questions/32602712/calling-protocol-default-implementation-from-regular-method

반응형