Ich habe ein Problem mit folgendem Code:
func generic1<T>(name : String){
}
func generic2<T>(name : String){
generic1<T>(name)
}
Das Ergebnis generic1 (name) führt zu einem Compilerfehler. "Eine generische Funktion kann nicht explizit spezialisiert werden."
Gibt es eine Möglichkeit, diesen Fehler zu vermeiden? Ich kann die Signatur der generic1-Funktion nicht ändern, daher sollte sie (String) -> Void sein
T
überhaupt in verwendetgeneric1()
? Wie würden Sie diese Funktion aufrufen , damit der Compiler auf den Typ schließen kann?func foo<T>() -> T { ... }
Das macht etwas mit einem Objektt
vom TypT
und der Rückgabet
. Eine explizite SpezialisierungT
würde es ermöglichent1
, eingegriffen zu werdenvar t1 = foo<T>()
. Ich wünschte, es gäbe auch eine Möglichkeit, Funktionen auf diese Weise aufzurufen. C # erlaubt esAntworten:
Ich hatte auch dieses Problem und fand eine Problemumgehung für meinen Fall.
In diesem Artikel hat der Autor das gleiche Problem
https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide
Das Problem scheint also zu sein, dass der Compiler irgendwie auf den Typ von T schließen muss. Es ist jedoch nicht erlaubt, einfach generisches <Typ> (Parameter ...) zu verwenden.
Normalerweise kann der Compiler nach dem Typ von T suchen, indem er die Parametertypen scannt, da hier in vielen Fällen T verwendet wird.
In meinem Fall war es ein bisschen anders, weil der Rückgabetyp meiner Funktion T war. In Ihrem Fall scheint es, dass Sie T in Ihrer Funktion überhaupt nicht verwendet haben. Ich denke, Sie haben gerade den Beispielcode vereinfacht.
Ich habe also folgende Funktion
Und zum Beispiel im Fall von
Der Compiler gibt mir den Fehler:
Um dem Compiler eine weitere Informationsquelle zu geben, aus der er auf den Typ von T schließen kann, müssen Sie den Typ der Variablen, in der der Rückgabewert gespeichert ist, explizit deklarieren.
Auf diese Weise weiß der Compiler, dass T eine ganze Zahl sein muss.
Insgesamt bedeutet dies einfach, dass Sie, wenn Sie eine generische Funktion angeben, mindestens T in Ihren Parametertypen oder als Rückgabetyp verwenden müssen.
quelle
func updateProperty<T>( propertyID : String )
let value = foo() as? Type
damit es in einem verwendet werden könnte,if
oderguard
das Ergebnis ist optional, aber es ist nicht ...Swift 5
Normalerweise gibt es viele Möglichkeiten, generische Funktionen zu definieren. Sie basieren jedoch auf einer Bedingung,
T
die alsparameter
oder als verwendet werden mussreturn type
.Danach müssen wir
T
beim Anruf angeben.Ref:
quelle
self.result = UIViewController.doSomething()
von alleine funktioniert, solange Sie die Eigenschaft bei der Deklaration eingegeben haben.doLastThing<UITextView>()
wird zu SwiftdoLastThing(UITextView.self)
, was zumindest nicht das Schlimmste ist. Besser, als komplizierte Ergebnisse explizit eingeben zu müssen. Vielen Dank für die Problemumgehung.Die Lösung verwendet den Klassentyp als Parameter (wie in Java).
Um dem Compiler mitzuteilen, mit welchem Typ er es zu tun hat, übergeben Sie die Klasse als Argument
Rufen Sie an als:
quelle
Sie benötigen hier kein Generikum, da Sie statische Typen haben (String als Parameter). Wenn Sie jedoch eine generische Funktion haben möchten, rufen Sie eine andere auf. Sie können Folgendes tun.
Generische Methoden verwenden
Verwenden einer generischen Klasse (Weniger flexibel, da die generische Klasse nur für einen Typ pro Instanz definiert werden kann)
quelle
Ich denke, wenn Sie eine generische Funktion angeben, sollten Sie einige der Parameter vom Typ T wie folgt angeben:
Wenn Sie die handle () -Methode aufrufen möchten, können Sie dies tun, indem Sie ein Protokoll schreiben und die Typbeschränkung für T angeben:
Sie können diese generische Funktion also mit String aufrufen:
und es wird kompiliert
quelle
Bisher verwendete meine persönliche Best Practice die Antwort von @ orkhan-alikhanov. Heute, wenn sie bei SwiftUI suchen und wie
.modifier()
undViewModifier
implementiert ist, fand ich eine andere Art und Weise (oder ist es eher eine Abhilfe?)Wickeln Sie einfach die zweite Funktion in eine
struct
.Beispiel:
Wenn dies der Fall ist, kann eine generische Funktion nicht explizit spezialisiert werden.
Dieser könnte helfen. Wickeln Sie die Erklärung von
generic1
in einstruct
:und nenne es mit:
Bemerkungen:
struct
ist ein gutes Beispiel. Die Problemumgehung hier hat nicht ein bisschen mehr Informationen - sondern übergibt den Compiler. Gleiche Informationen, aber unterschiedliche Ergebnisse? Dann stimmt etwas nicht. Wenn es sich um einen Compiler-Fehler handelt, kann er behoben werden.quelle
Ich hatte ein ähnliches Problem mit meiner generischen Klassenfunktion
class func retrieveByKey<T: GrandLite>(key: String) -> T?
.Ich könnte es nicht nennen,
let a = retrieveByKey<Categories>(key: "abc")
wenn Categories eine Unterklasse von GrandLite ist.let a = Categories.retrieveByKey(key:"abc")
zurückgegeben GrandLite, nicht Kategorien. Generische Funktionen leiten den Typ nicht basierend auf der Klasse ab, die sie aufruft.class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T?
gab mir einen Fehler, als ich versuchte,let a = Categories.retrieveByKey(aType: Categories, key: "abc")
gab mir einen Fehler, dass Categories.Type nicht in GrandLite konvertiert werden konnte, obwohl Categories eine Unterklasse von GrandLite ist. JEDOCH...class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T?
hat funktioniert, wenn ichlet a = Categories.retrieveByKey(aType: [Categories](), key: "abc")
anscheinend versucht habe , dass eine explizite Zuweisung einer Unterklasse nicht funktioniert, aber eine implizite Zuweisung mit einem anderen generischen Typ (Array) funktioniert in Swift 3.quelle
aType
als Instanz von angebenT
, anstatt sichCategories
selbst zu setzen . Bsp. :let a = Categories.retrieveByKey(aType: Categories(), key: "abc")
. Eine andere Lösung ist definierenaType: T.Type
. Dann rufen Sie die Methode alslet a = Categories.retrieveByKey(aType: Categories.self, key: "abc")