Nice programing

Swift : 제네릭 유형이 프로토콜을 준수하는지 확인

nicepro 2020. 11. 29. 12:15
반응형

Swift : 제네릭 유형이 프로토콜을 준수하는지 확인


다음과 같이 정의한 프로토콜이 있습니다.

protocol MyProtocol {
   ...
}

또한 일반 구조체가 있습니다.

struct MyStruct <T>  {
    ...
}

마지막으로 일반적인 기능이 있습니다.

func myFunc <T> (s: MyStruct<T>) -> T? {
   ...
}

T 유형이 MyProtocol을 준수하는지 함수 내부를 테스트하고 싶습니다. 본질적으로 나는 할 수 있기를 원합니다 (~ 의사 코드) :

let conforms = T.self is MyProtocol

그러나 이것은 컴파일러 오류를 발생시킵니다.

error: cannot downcast from 'T.Type' to non-@objc protocol type 'MyProtocol'
   let conforms = T.self is MyProtocol
                  ~~~~~~ ^  ~~~~~~~~~~

나는 또한 변화 같은 시도 T.self is MyProtocol.self, T is MyProtocol그리고 사용하는 ==대신을 is. 지금까지 나는 아무데도 가지 않았다. 어떤 아이디어?


조금 늦었지만 테스트로 프로토콜에 응답하는지 테스트 할 수 있습니다 as ?.

if let currentVC = myViewController as? MyCustomProtocol {
    // currentVC responds to the MyCustomProtocol protocol =]
}

편집 : 조금 더 짧게 :

if let _ = self as? MyProtocol {
    // match
}

그리고 가드 사용 :

guard let _ = self as? MyProtocol else {
    // doesn't match
    return
}

@Alex가 T유형이 아닌 프로토콜을 준수 하는지 확인하고 싶습니다 s. 그리고 일부 응답자는 명확하게 보지 못했습니다.

확인 T유형은 다음과 같은 프로토콜을 따릅니다.

if let _ = T.self as? MyProtocol.Type {
    //  T conform MyProtocol
}

또는

if T.self is MyProtocol.Type {
    //  T conform MyProtocol
}

가장 간단한 대답은 : 그렇게하지 마십시오. 대신 오버로딩 및 제약 조건을 사용하고 런타임에 동적으로 테스트하는 대신 컴파일 타임에 모든 것을 미리 결정하십시오. 런타임 유형 검사 및 컴파일 타임 제네릭은 스테이크와 아이스크림과 비슷합니다. 둘 다 좋지만 혼합하는 것은 약간 이상합니다.

다음과 같은 것을 고려하십시오.

protocol MyProtocol { }

struct MyStruct <T>  { let val: T }

func myFunc<T: MyProtocol>(s: MyStruct<T>) -> T? {
    return s.val
}

func myFunc<T>(s: MyStruct<T>) -> T? {
    return nil
}

struct S1: MyProtocol { }
struct S2 { }

let m1 = MyStruct(val: S1())
let m2 = MyStruct(val: S2())

myFunc(m1) // returns an instance of S1
myFunc(m2) // returns nil, because S2 doesn't implement MyProtocol

단점은 T가 런타임에 프로토콜을 지원하면 동적으로 설정할 수 없다는 것입니다.

let o: Any = S1()
let m3 = MyStruct(val: o)
myFunc(m3)  // will return nil even though o 
            // does actually implement MyProtocol

하지만 솔직히 말해서 일반 함수 내에서 그렇게해야합니까? 실제 유형이 무엇인지 확실하지 않은 경우 더 나은 옵션은 나중에 지연하고 알아 내기 위해 제네릭 함수 내에서 찌르는 것보다 미리 파악하는 것입니다.


여러 유형의 케이스를 처리하려는 경우 swift의 스위치 케이스 패턴 일치를 활용할 수도 있습니다 T.

func myFunc<T>(s: MyStruct<T>) -> T? {
    switch s {
    case let sType as MyProtocol:
        // do MyProtocol specific stuff here, using sType
    default:
        //this does not conform to MyProtocol
    ...
    }
}

You need declare protocol as @objc:

@objc protocol MyProtocol {
    ...
} 

From Apple's "The Swift Programming Language" book:

You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance.

Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types.


let conforms = T.self is MyProtocol.Type

참고URL : https://stackoverflow.com/questions/28124684/swift-check-if-generic-type-conforms-to-protocol

반응형