2017-07-08 43 views
1

在通用函數中,我想測試符合特定協議的給定對象是否爲給定類型。如果具體的類類型作爲參數傳遞給檢查函數,它會很好用。然而,當我使用一個變量的類型(使用三元運算符),我得到一個錯誤:使用符合協議的類型變量調用通用函數

Cannot invoke ' isObject ' with an argument list of type ' (AnyObject, of: P.Type) '

鑄造另外的類型變量P.Protocol並沒有幫助,因爲:

In argument type ' P.Protocol ', ' P ' does not conform to expected type ' P '

protocol P { 
    static var descr: String {get} 
} 

class A: P { 
    static let descr = "class A" 
} 

class B: P { 
    static let descr = "class B" 
} 

class Test { 
    func isObject<T:P>(_ object: AnyObject, of type: T.Type) -> Bool { 
     print("descr: \(type.descr)") 
     return object is T 
    } 
} 

let a = A() 
let type = (false ? A.self : B.self) as P.Type //as! P.Protocol 
let test = Test() 

test.isObject(a, of: type) 

回答

0

的問題是,與通用佔位符T,當T是協議類型PT.TypeP.ProtocolP.Type。換句話說,它需要一個元類型來描述協議本身,而不是描述符合協議的類型的元類型。這個區別很重要,因爲protocols don't conform to themselves

你的情況的一個解決方案是引入圍繞P.Type元類型的包裝,它在初始化程序中使用通用佔位符來存儲閉包以執行is檢查。

struct AnyPType { 

    let base: P.Type 
    private let _isInstance: (Any) -> Bool 

    /// Creates a new AnyType wrapper from a given metatype. 
    /// The passed metatype's value **must** match its static value, i.e `T.self == base`. 
    init<T : P>(_ base: T.Type) { 
     precondition(T.self == base, "The static value \(T.self) and dynamic value \(base) of the passed metatype do not match") 
     self.base = T.self 
     self._isInstance = { $0 is T } 
    } 

    func isInstance(_ instance: Any) -> Bool { 
     return _isInstance(instance) 
    } 
} 

這是我表現出我的回答to this Q&A包裝,我在其中也展示瞭如何解除T.self == base對蘋果平臺的限制(但這個限制不應該是一個問題的專門版本的案件)。

您現在可以使用的包裝,像這樣:

class Test { 
    func isObject(_ object: Any, of type: AnyPType) -> Bool { 
     print("descr: \(type.base.descr)") 
     return type.isInstance(object) 
    } 
} 

let type = AnyPType(A.self) // or AnyPType(B.self) 

print(Test().isObject(A(), of: type)) 

// descr: class A 
// true 
相關問題