Ich habe ein Protokoll, das ich so definiert habe:
protocol MyProtocol {
...
}
Ich habe auch eine generische Struktur:
struct MyStruct <T> {
...
}
Endlich habe ich eine generische Funktion:
func myFunc <T> (s: MyStruct<T>) -> T? {
...
}
Ich möchte innerhalb der Funktion testen, ob der Typ T MyProtocol entspricht. Im Wesentlichen möchte ich in der Lage sein (~ Pseudocode):
let conforms = T.self is MyProtocol
Dies führt jedoch zu einem Compilerfehler:
error: cannot downcast from 'T.Type' to non-@objc protocol type 'MyProtocol'
let conforms = T.self is MyProtocol
~~~~~~ ^ ~~~~~~~~~~
Ich habe auch Variationen ausprobiert, wie T.self is MyProtocol.self
, T is MyProtocol
und die Verwendung ==
statt is
. Bisher bin ich nirgendwo hingekommen. Irgendwelche Ideen?
Ein bisschen spät, aber Sie können testen, ob etwas mit dem
as ?
Test auf das Protokoll reagiert :if let currentVC = myViewController as? MyCustomProtocol { // currentVC responds to the MyCustomProtocol protocol =] }
EDIT: etwas kürzer:
if let _ = self as? MyProtocol { // match }
Und mit einer Wache:
guard let _ = self as? MyProtocol else { // doesn't match return }
quelle
T
, aber die Frage fragt nach generischem TYP. Somit ist Carlos Antwort besser: stackoverflow.com/a/52787263/1311272Die einfachste Antwort lautet: Tu das nicht. Verwenden Sie stattdessen Überladung und Einschränkungen und bestimmen Sie alles zur Kompilierungszeit im Voraus, anstatt zur Laufzeit dynamisch zu testen. Runtime Type Checking und Generika zur Kompilierungszeit sind wie Steak und Eis - beide sind nett, aber das Mischen ist etwas seltsam.
Betrachten Sie so etwas:
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
Der Nachteil ist, dass Sie nicht dynamisch feststellen können, ob T zur Laufzeit ein Protokoll unterstützt:
let o: Any = S1() let m3 = MyStruct(val: o) myFunc(m3) // will return nil even though o // does actually implement MyProtocol
Aber, ganz ehrlich, müssen Sie das wirklich in Ihrer generischen Funktion tun? Wenn Sie sich nicht sicher sind, um welchen Typ es sich tatsächlich handelt, ist es möglicherweise besser, dies im Voraus herauszufinden, als es auf einen späteren Zeitpunkt zu verschieben und es in einer generischen Funktion zu finden, um dies herauszufinden.
quelle
JSONEncodable
, das erforderlich istinit(json: JSON) throws
. Wir wollenArray
implementierenJSONEncodable
, aber nur, wenn seine Elemente auch sindJSONEncodable
. Wir können eine Vererbungsklausel nicht mit Einschränkungen kombinieren, daher müssen wir in unserer Implementierung voninit
eine Art Typprüfung verwenden und möglicherweise einen Fehler auslösen, wenn diesElement
nicht der Fall istJSONEncodable
. Leider scheint dies AFAICT nicht möglich zu sein.MyStruct
mit oder ohne Hinweis konstruieren kann<Type>
und es kann sagen, was zu tun ist. Für andere, die den Code ausprobieren, benötigt Swift 4 ein_
Argument für das erste KonstruktorSie können auch den Switch Case Pattern Matching von Swift nutzen , wenn Sie mehrere Fälle vom Typ behandeln möchten
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 ... } }
quelle
let konform = T.self ist MyProtocol.Type
quelle
let conforms = T.self is MyProtocol
.Sie müssen das Protokoll wie folgt deklarieren
@objc
:@objc protocol MyProtocol { ... }
Aus Apples Buch "The Swift Programming Language":
quelle
@objc protocol MyProtocol {} struct MyStruct <T> {} func myFunc <T> (s: MyStruct<T>) -> T? { let conforms = T.self is MyProtocol }
func myFunc<T: MyProtocol>(...) -> T?
Eine moderne Antwort lautet wie folgt: (Swift 5.1)
func myFunc < T: MyProtocol> (s: MyStruct<T>) -> T? { ... }
quelle
Für Testfälle überprüfe ich die Konformität wie folgt:
let conforms: Bool = (Controller.self as Any) is Protocol.Type
quelle