Swift:检查genericstypes是否符合协议
我有一个协议,我这样定义:
protocol MyProtocol { ... }
我也有一个通用的结构:
struct MyStruct <T> { ... }
最后我有一个通用的function:
func myFunc <T> (s: MyStruct<T>) -> T? { ... }
如果Ttypes符合MyProtocol,我想在函数内部进行testing。 本质上我想能够做到(〜伪代码):
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
。 到目前为止,我没有得到任何地方。 有任何想法吗?
有点晚,但你可以testing是否有什么东西响应协议与as ?
testing:
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 }
最简单的答案是:不要这样做。 相反,使用重载和约束,并在编译时预先确定所有的东西,而不是在运行时dynamic地testing东西。 运行时types检查和编译时generics就像牛排和冰淇淋 – 两者都很好,但混合起来有点奇怪。
考虑这样的事情:
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在运行时支持协议,则不能dynamicbuild立:
let o: Any = S1() let m3 = MyStruct(val: o) myFunc(m3) // will return nil even though o // does actually implement MyProtocol
但是,诚实地说,你真的需要在你的generics函数中这么做吗? 如果你不确定什么是实际的types,那么更好的select可能是预先计算出来,而不是稍后推迟,并在一个通用函数中找出它来找出结果。
我不得不说,@Alex想要检查T
types是否符合协议而不是s
。 还有一些回答者没有看清楚。
检查T
型符合这样的协议:
if let _ = T.self as? MyProtocol.Type { // T conform MyProtocol }
要么
if T.self is MyProtocol.Type { // T conform MyProtocol }
你也可以利用swift的switch case模式匹配 ,如果你想处理多个T
types的情况:
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 ... } }
您需要将协议声明为@objc
:
@objc protocol MyProtocol { ... }
从苹果的“Swift编程语言”一书中:
只有在协议标记为@objc属性时才能检查协议一致性,如上面的HasArea协议所示。 这个属性表明该协议应该暴露给Objective-C代码,在使用Cocoa和Objective-C的Swift中有描述。 即使您不与Objective-C进行互操作,如果您希望能够检查协议一致性,您也需要使用@objc属性标记您的协议。
还要注意,@objc协议只能由类来采用,而不能通过结构或枚举。 如果您将协议标记为@objc以检查一致性,您将只能将该协议应用于类types。