J'ai un problème avec le code suivant:
func generic1<T>(name : String){
}
func generic2<T>(name : String){
generic1<T>(name)
}
le résultat generic1 (nom) à l'erreur du compilateur "Impossible de spécialiser explicitement une fonction générique"
Y a-t-il un moyen d'éviter cette erreur? Je ne peux pas changer la signature de la fonction generic1, donc ça devrait être (String) -> Void
T
utilisé dansgeneric1()
? Comment voulez - vous appeler cette fonction, de sorte que le compilateur peut déduire le type?func foo<T>() -> T { ... }
ça fait quelque chose avec un objett
de typeT
et le returnt
. Une spécialisation expliciteT
permettraitt1
d'être impliquévar t1 = foo<T>()
. J'aurais aimé qu'il y ait un moyen d'appeler des fonctions de cette façon aussi. C # le permetRéponses:
J'ai également eu ce problème et j'ai trouvé une solution de contournement pour mon cas.
Dans cet article, l'auteur a le même problème
https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide
Le problème semble donc être que le compilateur doit en quelque sorte déduire le type de T. Mais il n'est pas permis d'utiliser simplement le <type> générique (params ...).
Normalement, le compilateur peut rechercher le type de T, en analysant les types de paramètres car c'est là que T est utilisé dans de nombreux cas.
Dans mon cas, c'était un peu différent, car le type de retour de ma fonction était T. Dans votre cas, il semble que vous n'ayez pas du tout utilisé T dans votre fonction. Je suppose que vous venez de simplifier l'exemple de code.
J'ai donc la fonction suivante
Et en cas de, par exemple
le compilateur me donne l'erreur:
Ainsi, pour donner au compilateur une autre source d'informations pour déduire le type de T, vous devez déclarer explicitement le type de la variable dans laquelle la valeur de retour est enregistrée.
De cette façon, le compilateur sait que T doit être un entier.
Donc, je pense que dans l'ensemble, cela signifie simplement que si vous spécifiez une fonction générique, vous devez au moins utiliser T dans vos types de paramètres ou comme type de retour.
la source
func updateProperty<T>( propertyID : String )
let value = foo() as? Type
donc il pourrait être utilisé dans unif
ou siguard
le résultat est optionnel, mais ce n'est pas le cas ...Swift 5
En règle générale, il existe de nombreuses façons de définir des fonctions génériques. Mais ils sont basés sur des conditions qui
T
doivent être utilisées en tant queparameter
, ou en tant quereturn type
.Après cela, il faut prévoir
T
lors de l'appel.Réf:
la source
self.result = UIViewController.doSomething()
travaux seuls tant que vous avez tapé la propriété lorsque vous la déclarez.doLastThing<UITextView>()
devient SwiftdoLastThing(UITextView.self)
, ce qui n'est ... pas le pire, du moins. Mieux que d'avoir à taper explicitement des résultats compliqués. Merci pour la solution de contournement.La solution prend le type de classe comme paramètre (comme en Java)
Pour indiquer au compilateur de quel type il a affaire, passez la classe en argument
Appelez en tant que:
la source
Vous n'avez pas besoin d'un générique ici car vous avez des types statiques (String en tant que paramètre), mais si vous voulez qu'une fonction générique en appelle une autre, vous pouvez faire ce qui suit.
Utilisation de méthodes génériques
Utilisation d'une classe générique (moins flexible car le générique peut être défini pour 1 type uniquement par instance)
la source
Je pense que lorsque vous spécifiez une fonction générique, vous devez spécifier certains des paramètres de type T, comme suit:
et si vous voulez appeler la méthode handle (), vous pouvez le faire en écrivant le protocole et en spécifiant la contrainte de type pour T:
vous pouvez donc appeler cette fonction générique avec String:
et il compilera
la source
Jusqu'à présent, mes meilleures pratiques personnelles ont utilisé la réponse de @ orkhan-alikhanov. Aujourd'hui, quand on regarde SwiftUI et comment
.modifier()
etViewModifier
est mis en œuvre, j'ai trouvé une autre façon (ou est - il plus une solution de contournement?)Enveloppez simplement la deuxième fonction dans un fichier
struct
.Exemple:
Si celui-ci vous donne le "Impossible de spécialiser explicitement une fonction générique"
Celui-ci pourrait aider. Enveloppez la déclaration de
generic1
dans unstruct
:et appelez-le avec:
Remarques:
struct
est un bon exemple. La solution de contournement ici n'a pas un peu plus d'informations - mais passe le compilateur. Mêmes informations, mais résultats différents? Alors quelque chose ne va pas. S'il s'agit d'un bogue du compilateur, il peut être corrigé.la source
J'ai eu un problème similaire avec ma fonction de classe générique
class func retrieveByKey<T: GrandLite>(key: String) -> T?
.Je ne pourrais pas l'appeler là
let a = retrieveByKey<Categories>(key: "abc")
où Catégories est une sous-classe de GrandLite.let a = Categories.retrieveByKey(key:"abc")
renvoyé GrandLite, pas Catégories. Les fonctions génériques ne déduisent pas de type en fonction de la classe qui les appelle.class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T?
m'a donné une erreur lorsque j'ai essayélet a = Categories.retrieveByKey(aType: Categories, key: "abc")
m'a donné une erreur qu'il ne pouvait pas convertir Categories.Type en GrandLite, même si Categories est une sous-classe de GrandLite. TOUTEFOIS...class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T?
a fonctionné si j'essayaislet a = Categories.retrieveByKey(aType: [Categories](), key: "abc")
apparemment une affectation explicite d'une sous-classe ne fonctionne pas, mais une affectation implicite utilisant un autre type générique (tableau) fonctionne dans Swift 3.la source
aType
comme instance deT
, au lieu de se mettreCategories
. Ex:let a = Categories.retrieveByKey(aType: Categories(), key: "abc")
. Une autre solution est de définiraType: T.Type
. Ensuite, appelez la méthode commelet a = Categories.retrieveByKey(aType: Categories.self, key: "abc")