Swift Equatable sur un protocole
Je ne pense pas que cela peut être fait, mais je vais la poser quand même. J'ai un protocole:
protocol X {}
Et une classe:
class Y:X {}
Dans le reste de mon code je me réfère à tout en utilisant le protocole X. Dans ce code, je voudrais être en mesure de faire quelque chose comme:
let a:X = ...
let b:X = ...
if a == b {...}
Le problème est que si j'essaie de mettre en œuvre Equatable
:
protocol X: Equatable {}
func ==(lhs:X, hrs:X) -> Bool {
if let l = lhs as? Y, let r = hrs as? Y {
return l.something == r.something
}
return false
}
L'idée de l'essayer et de permettre l'utilisation de ==
tout en cachant les implémentations derrière le protocole.
Swift n'aime pas cela, mais parce que Equatable
a Self
références et de ne plus me permettre de l'utiliser comme un type. Seulement comme un argument générique.
Si quelqu'un a trouvé un moyen pour appliquer un opérateur à un protocole sans le protocole de devenir inutilisable en tant que type?
Vous devez vous connecter pour publier un commentaire.
Si vous mettre directement en œuvre
Equatable
sur un protocole, il ne sera pas plus être utilisable comme un type, qui va à l'encontre de l'objectif de l'utilisation d'un protocole. Même si vous venez de mettre en œuvre==
fonctions sur les protocoles sansEquatable
de la conformité, les résultats peuvent être erronés. Voir ce post sur mon blog pour une démonstration de ces questions:https://khawerkhaliq.com/blog/swift-protocols-equatable-part-one/
L'approche que j'ai trouvé le mieux est d'utiliser le type de l'effacement. Cela permet de faire
==
comparaisons pour les types de protocole (enveloppé dans le type de gommes à effacer). Il est important de noter que, tandis que nous continuons à travailler au niveau du protocole, le==
comparaisons sont délégués de la sous-types de béton pour garantir des résultats corrects.J'ai construit un type de gomme à l'aide de votre exemple et ajouté un peu de code de test à la fin. J'ai ajouté une constante de type
String
au protocole et a créé deux conformes types (les structures sont les plus faciles pour fins de démonstration) pour être en mesure de tester les différents scénarios.Pour une explication détaillée du type d'effacement de la méthodologie utilisée, vérifiez la partie deux de la au-dessus de blog:
https://khawerkhaliq.com/blog/swift-protocols-equatable-part-two/
Le code ci-dessous devrait soutenir la comparaison d'égalité que vous avez voulu mettre en œuvre. Vous avez juste à envelopper le type de protocole dans un type de gomme à l'instance.
Noter que, depuis le type de gomme est conforme au protocole, vous pouvez utiliser des instances du type gomme n'importe où une instance du type de protocole est prévu.
Espère que cette aide.
La raison pour laquelle vous devriez penser deux fois avant d'avoir un protocole conforme à
Equatable
est que, dans de nombreux cas, il n'a tout simplement pas de bon sens. Considérons cet exemple:Vous faites allusion à la vérification de type à l'intérieur de la mise en œuvre de
==
mais le problème, c'est que vous n'avez aucune information à propos des types au-delà de leur êtrePet
s et vous ne savez pas toutes les choses qui pourraient être unPet
(peut-être que vous allez ajouter unBird
etRabbit
plus tard). Si vous avez vraiment besoin de ceci, une autre approche peut être de la modélisation de la façon dont les langages tels que C# mettre en œuvre l'égalité, en faisant quelque chose comme:À quel point si vous le voulez bien, vous pourriez mettre en œuvre
==
sans la mise en œuvre deEquatable
:Une chose que vous avez à regarder dehors pour dans ce cas est l'héritage que. Parce que vous pourriez abattu un hériter du type et de supprimer les informations qui pourraient rendre
isEqualTo
pas logique.La meilleure façon de le faire est de ne mettre en œuvre l'égalité sur la class/struct eux-mêmes et d'utiliser un autre mécanisme de vérification de type.
isEqual
option (à partir de Java), mais dans l'espoir de garder les choses simples parce que j'ai un cas où j'ai différentes classes qui représentent la même contextural chose, et donc je voudrais pouvoir être considérés comme égaux, même si elles sont différentes implémentations.Ne savez pas pourquoi vous avez besoin de toutes les instances de votre protocole pour se conformer à
Equatable
, mais je préfère laisser les classes de mettre en œuvre l'égalité des méthodes.Dans ce cas, je vous laisse le protocole simple:
Si vous avez besoin qu'un objet qui est conforme à
MyProtocol
est égalementEquatable
vous pouvez utiliserMyProtocol & Equatable
comme une contrainte de type:De cette façon, vous pouvez garder votre cahier des charges clair et de laisser les sous-classes de mettre en œuvre leur égalité méthode uniquement si nécessaire.
peut-être que ce sera utile pour vous:
J'ai toujours le conseiller à l'encontre de la mise en œuvre de
==
l'utilisation du polymorphisme. C'est un peu une odeur de code. Si vous voulez donner le cadre de l'utilisateur de quelque chose, il peut tester l'égalité avec alors vous devriez vraiment être un distributeur destruct
, pas unprotocol
. Cela ne veut pas dire qu'il ne peut pas être leprotocol
s qui sont des distributeurs de lastruct
s si:Je pense que ce plus efficacement communique votre intention, qui est en gros "vous avez ces choses et vous ne savez pas si ce sont les mêmes choses, mais vous ne savez qu'ils ont le même ensemble de propriétés et vous pouvez tester si ces propriétés sont les mêmes." C'est assez proche de la façon dont je voudrais mettre en œuvre que
Money
exemple.Vous avez à mettre en œuvre un extension du protocole contraint à votre type de classe. À l'intérieur de cette extension, vous devriez mettre en œuvre les
Equatable
opérateur.Mais laissez-moi vous recommandons d'ajouter l'opérateur de la mise en œuvre de votre classe. Keep It Simple 😉
Tous les gens qui disent que vous ne pouvez pas mettre en œuvre
Equatable
pour un protocole, il suffit de ne pas essayez assez dur. Voici la solution (Swift 4.1) pour votre protocoleX
exemple:Et ça marche!!!
Le seul problème est que vous ne pouvez pas écrire
let a: X = Y()
en raison de "Protocole ne peut être utilisé comme une contrainte générique" erreur.