1

기본 매개 변수가있는 정적 메서드가있는 프로토콜이 있습니다. 프로토콜을 구현하는 클래스에서 기본값을 변경하려고합니다. 본질적으로 클래스와 슈퍼로 쉽게 수행 할 수 있습니다.
프로토콜에 연결된 유형이없는 경우에만 해결책을 얻을 수 있습니다.프로토콜에 연결된 형식이있을 때 일반 메서드에서 프로토콜을 기본 구현으로 호출

다음 코드는 작동하지만 관련 유형 선언의 주석을 해제하면 바로 컴파일되지 않습니다. 이 컴파일되지 않는 이유

protocol Protocol { 
// associatedtype AssociatedType 
} 

extension Protocol { 
    func sayHello(name: String = "World") { 
     print("Hello, \(name)!") 
    } 
} 

class Class<T>: Protocol { 
    typealias AssociatedType = T 

    func sayHello(name: String = "Stack Overflow") { 
     // Uncommenting the Protocol.AssociatedType causes: 
     // Protocol can only be used as a generic constraint because it has associated type requirements 
     (self as Protocol).sayHello(name) 
    } 
} 

Class<()>().sayHello() 

나는 이해한다 : ProtocolAssociatedType에 대한 구체적인 유형이 없습니다.
어쩌면 질문은 "내가 프로토콜을 명시 적으로 전문화 할 수 있습니까?"라고 대답해야합니다. 그 대답은 "아니오"입니다.

부분적인 해결책이 있습니다. 그러나 그것이 효과가 있더라도, 그것은 빤다.
특히 내가 sayHello이 공개 된 라이브러리를 작성 중이므로 다음 해결 방법을 사용하면 두 번째 프로토콜이 공개되어야하지만 쓸모가 없습니다. 내 sayHello 연관된 유형을 사용하기 때문에,

protocol Parent {} 

protocol Protocol: Parent { 
    associatedtype AssociatedType 
} 

extension Parent { 
    func sayHello(name: String = "World") { 
     print("Hello, \(name)!") 
    } 
} 

class Class<T>: Protocol { 
    typealias AssociatedType = T 

    func sayHello(name: String = "Stack Overflow") { 
     (self as Parent).sayHello(name) 
    } 
} 

Class<()>().sayHello() 

그러나 이것은 나를 위해 작동하지 않습니다
여기에 해결 방법입니다. 따라서 다른 프로토콜로 추출 할 수 없습니다.

그냥 내가 분명 해요 확인하기 위해 여기 난 단지 프로토콜의 클래스를 대체하고 싶은 내용은 다음과 같습니다

class Protocol<T> { 
    func sayHello(name: String = "World") { 
     print("Hello, \(name)!") 
    } 
} 

class Class<T>: Protocol<T> { 
    override func sayHello(name: String = "Stack Overflow") { 
     super.sayHello(name) 
    } 
} 

Class<()>().sayHello() 

답변

1

당신은 프로토콜의 유산을 재발견하기 위해 노력하고, 그리고 그런 없다 맡은 일. 그러나 당신이 말하는 것을 얻는 것은 사소한 일입니다. 그냥 무슨 뜻인지 말해줘. 당신은 "나는 상속받은 것을하고 싶다"는 뜻이 아닙니다. "나는 일반적인 행동을하고 싶다." 그 일반적인 행동의 이름을 알려주세요. 이것은 당신이 의미하는 모호성을 제거합니다.

protocol Protocol { 
     associatedtype AssociatedType 
} 

extension Protocol { 
    // Put the default behavior on the protocol, not on the instance 
    // Of course you could also put it on the instance if that were convenient. 
    static func defaultSayHello(_ name: String = "World") { 
     print("Hello, \(name)!") 
    } 

    // If you want a default on the instance, too, provide one that we an override 
    func sayHello(_ name: String = "World") { 
     Self.defaultSayHello(name) 
    } 
} 

class Class<T>: Protocol { 
    typealias AssociatedType = T 

    func sayHello(name: String = "Stack Overflow") { 
     // Now the default behavior lives on my type 
     Class.defaultSayHello(name) 
    } 
} 

// But other types can get default behavior 
class OtherClass<T>: Protocol { 
    typealias AssociatedType = T 
} 

Class<()>().sayHello() // Hello, Stack Overflow! 
OtherClass<()>().sayHello() // Hello, World! 

이것에 대해 하나 개의 실망스러운 부분은 스위프트가 Protocol의 구현에 defaultSayHello을 제한 할 수있는 방법을 제공하지 않는다는 점이다. 그래서 기술적으로 누구나 그것을 부를 수 있습니다. 외부인이해서는 안되는 것을 가리 키기 위해 접두사로 _을 붙이는 것이 때때로 가치가 있습니다. 이는 프로토콜에서 기본적인 액세스 제어 문제이며이 특정 질문과 관련이 없습니다. 내 구현자가 스스로 사용할 수 있지만 무작위로 호출해서는 안되는 모든 시간이 다가옵니다. " 스위프트는 오늘 그 해결책이 없습니다.

+0

필자가 지적했듯이 내가 피하려고하는 공개 API를 오염시키기 때문에이 대답을 받아들이지 않습니다. 그것은 나에게 영감을 주었고, 그래서 나는 내 자신의 대답을 게시했다. – ThinkChaos

0

롭 네이피어 (Rob Napier)의 답변에서 영감을 얻은 다음 여기에 나와 있습니다. 기본값의 양호한 오버로드 :

protocol Protocol { 
    associatedtype AssociatedType 
} 

extension Protocol { 
    func sayHello(name: String = "World") { 
     print("Hello, \(name)!") 
    } 
} 

class Class<T>: Protocol { 
    typealias AssociatedType = T 

    func sayHello() { 
     self.sayHello("Stack Overflow") 
    } 
} 

Class<()>().sayHello()  // Hello, Stack Overflow! 
Class<()>().sayHello("you") // Hello, you! 

이것은 내 필요에 맞는 것이지만 질문에 대답하지 않습니다. 그래서 저는 100 % 만족하지 않습니다.
Rust는 특성/프로토콜이 X<T>과 관련 유형 모두를 사용하여 일반화 될 수 있도록 허용하여이 하나의 권한을 얻습니다.

관련 문제