스위프트의 다중 유형 제약


133

이 프로토콜이 있다고 가정 해 봅시다.

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}

이제 제네릭 형식을 취하는 함수를 원하지만 해당 형식을 따라야 할 SomeProtocol수 있습니다.

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}

그러나 여러 프로토콜에 대한 유형 제약 조건을 추가하는 방법이 있습니까?

func bothFunc<T: SomeProtocol | SomeOtherProtocol>(arg: T) {

}

비슷한 것들이 쉼표를 사용하지만이 경우 다른 유형의 선언을 시작합니다. 여기 내가 시도한 것이 있습니다.

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>

이것은 스위프트 문서가 제네릭 챕터에서 이것을 언급하지 않았기 때문에 특별히 관련된 질문입니다.
Bruno Philipe

답변:


241

당신은 사용할 수 있습니다 where 절 은 (모두 충족되어야합니다 그중를) 원하는 쉼표로 구분대로 많은 요구 사항으로 지정할 수 있습니다

스위프트 2 :

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}

스위프트 3 & 4 :

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}

또는 더 강력한 where 절 :

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}

물론 프로토콜 구성 (예 :)을 사용할 수 protocol<SomeProtocol, SomeOtherProtocol>있지만 유연성이 떨어집니다.

Using를 where사용하면 여러 유형이 관련된 경우를 처리 할 수 ​​있습니다.

여러 위치에서 재사용하기 위해 프로토콜을 작성하거나 작성된 프로토콜에 의미있는 이름을 부여 할 수 있습니다.

스위프트 5 :

func someFunc(arg: SomeProtocol & SomeOtherProtocol) { 
    // stuff
}

프로토콜이 논쟁 옆에 있기 때문에 이것은 더 자연스러운 느낌입니다.


Geez 이것은 논리적이지 않지만, 나는 이것에 대한 감사 스패머 중 하나가되고 싶다는 것을 알고 있다는 것이 좋았습니다. 필요한지 한 달 만에 이것을 깨닫지 못했습니다.
Mathijs Segers

3
형식 제약 조건 식에서 클래스 및 구조체로 동일한 작업을 수행하는 방법은 무엇입니까? 예를 들어 <T where T:SomeStruct, T:AnotherStruct>? 클래스의 경우 컴파일러는 이것을 "T는 둘 다의 서브 클래스"라고 해석하는 것으로 보이며, 구조체의 경우이를 불평합니다 "Type 'T' constrained to non-protocol type".
Jarrod Smith

OP : 질문 프로토콜 구성의 구체적인 예는 바람직한 방법 이어야 합니다. 위의 솔루션은 유효하지만 imho는 불필요하게 함수 서명을 어지럽 힙니다. 또한 프로토콜 제약을 예를 들어 형식 제약 조건으로 사용하면 where추가 형식 / 다른 사용법, 예 func someFunc<U, T: protocol<SomeProtocol, SomeOtherProtocol> where T.SubType == U>(arg: T, arg2: U) { ... }를 들어 형식 별칭 SubType에 대한 절을 계속 사용할 수 있습니다 SomeProtocol.
dfri

1
이것은 swift3에서 더 이상 사용되지 않으며 다음을 사용하는 것이 좋습니다. func someFunc <T> (arg : T) 여기서 T : SomeProtocol, T : SomeOtherProtocol {
Cristi Băluță

2
T가 특정 객체 유형이어야하고 특정 프로토콜을 구현해야한다고 신속하게 말할 수있는 방법이 있습니까?
Georg

73

두 가지 가능성이 있습니다.

  1. Jiaaro의 답변에 표시된 where 절 을 사용하십시오 .

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
  2. 당신은 사용하는 프로토콜 구성 유형 :

    func someFunc<T : protocol<SomeProtocol, SomeOtherProtocol>>(arg: T) {
        // do stuff
    }

2
imo 두 번째 솔루션이 더 예쁘다.이 답변을 위해 두 가지 옵션을 제시하는 것이 더 완벽하다.
Mathijs Segers

2
번호 2는을 선언 할 때 Swift 2에서 저에게 효과적입니다 typealias. 감사!
Bruno Philipe

19

Swift 3.0으로의 진화는 약간의 변화를 가져옵니다. 우리의 두 가지 선택은 이제 조금 다르게 보입니다.

whereSwift 3.0에서 절 사용 :

where절은 이제 가독성을 개선하기 위해 함수 서명의 끝으로 이동하고있다. 다중 프로토콜 상속은 이제 다음과 같습니다 :

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {

}

protocol<>Swift 3.0 에서 구문 사용 :

구성을 사용하는 protocol<>구성은 더 이상 사용되지 않습니다. 이전 protocol<SomeProtocol, SomeOtherProtocol>은 다음과 같습니다.

func someFunc<T:SomeProtocol & SomeOtherProtocol>(arg: T) {

}

참고 문헌.

변경 사항에 대한 자세한 내용 where은 다음을 참조 하십시오. https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

프로토콜 <> 구문의 변경 사항에 대한 자세한 내용은 다음을 참조 하십시오. https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md


13

Swift 3는 함수를 선언하는 최대 3 가지 방법을 제공합니다.

protocol SomeProtocol {
    /* ... */
}

protocol SomeOtherProtocol {
    /* ... */        
}

1. &연산자 사용

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    /* ... */
}

2. 사용 where

func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
    /* ... */
}

3. where절과 &연산자 사용

func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
    /* ... */        
}

또한 typealias함수 선언을 단축하기 위해 사용할 수 있습니다 .

typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol

func someFunc<T: RequiredProtocols>(arg: T) {
    /* ... */   
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.