Comment créer un Dictionnaire peut contenir quoi que ce soit dans la Clé? ou tous les type capable de tenir
Je veux créer un Dictionary
qui ne limite pas le type de clé (comme NSDictionary
)
J'ai donc essayé
var dict = Dictionary<Any, Int>()
et
var dict = Dictionary<AnyObject, Int>()
résultant
error: type 'Any' does not conform to protocol 'Hashable'
var dict = Dictionary<Any, Int>()
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Any, Int>()
^~~~~~~~~~~~~~~~~~~~~~
OK, je vais utiliser Hashable
var dict = Dictionary<Hashable, Int>()
mais
error: type 'Hashable' does not conform to protocol 'Equatable'
var dict = Dictionary<Hashable, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Hashable, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~~
Donc Hashable
hérité de Equatable
mais il n'est pas conforme à Equatable
??? Je ne comprends pas...
De toute façon, continuer à essayer
typealias KeyType = protocol<Hashable, Equatable> //KeyType is both Hashable and Equatable
var dict = Dictionary<KeyType, Int>() // now you happy?
avec pas de chance
error: type 'KeyType' does not conform to protocol 'Equatable'
var dict = Dictionary<KeyType, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'KeyType' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:6:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<KeyType, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~
Je suis perdu maintenant, comment puis-je faire compilateur heureux avec mon code?
Je veux utiliser le dictionnaire comme
var dict = Dictionary<Any, Int>()
dict[1] = 2
dict["key"] = 3
dict[SomeEnum.SomeValue] = 4
Je sais que je peux utiliser Dictionary<NSObject, Int>
, mais il n'est pas vraiment ce que je veux.
- faire une classe qui est conforme à Hashable et Equatable?
- comment est-ce utile? il limite le type de clé à cette classe seulement. et si vraiment vous dire de faire un nouveau
protocol
, qui ne sera pas vous aider. parce que je ne peux pas les extensions de toutes les autres classes afin de les rendre conformes mon protocole - eh bien, d'une façon ou d'une autre, vous devez convaincre un Dictionnaire de votre générique type de clé peut être à la fois hachée et comparés pour l'égalité, car c'est ainsi qu'un dictionnaire des œuvres
- sinon, vous pourriez vous mettre en place votre propre dictionnaire avec votre propre table de hachage/comparer les méthodes
- n'ont aucune idée sur la façon générique peut aider. et je me bats avec le type de contrôleur, même avec mon propre dictionnaire de la mise en œuvre, je vais avoir le même problème. Parce que le type de vérificateur va faire la même chose pour moi encore une fois sur le nouveau type de dictionnaire.
- Est-il une raison
AnyObject
n'est pas conforme àHashable
etEquatable
? Est-il connu sous type deAnyObject
qui ne serait pas faire le bien en ce? - que voulez-vous dire?
AnyObject
est@class_protocol protocol AnyObject {}
, qui, par définition, n'est pas conforme à un protocole - Bon, je sais que ça ne marche pas, j'étais juste (philosophiquement), en méditant ce que le monde serait comme si il l'a fait, comme suit:
@class_protocol protocol BetterAnyObject : NSObjectProtocol, Equatable, Hashable {}
- c'est fondamentalement
NSObject
- Je pense que cela pourrait être la réponse à votre question, puis - si un
Dictionary
exige que ses touches d'être à la fois equatable et hashable, etNSObject
est le plus générique type qui implémente les deux, c'est ce que vous avez besoin pour utiliser votre clé. (Même si je sais que vous mentionnez ne pas vouloir l'utiliser, il semble que la seule option avec ce qui est actuellement disponible.) - eh bien, c'est la solution de repli. ce qui m'arrêter de mettre
struct
etenum
dans le dictionnaire. - Ce qui est logique. Si le compilateur ne peut pas garantir qu'un
enum
seront en mesure de fournir un hachage lors de l'exécution, et laDictionary
exige de ses touches, vous ne pouvez pas utiliserenum
types de clés. Comme un autre intervenant mentionne, votre meilleur pari pourrait être une sous-classe personnalisée qui prend en charge le protocole enum/struct clés. - Je suppose que je peux avoir la classe wrapper pour tenir enum et struct. mais le compilateur ne peut garantir que parce que je peux faire
enum
(etstruct
) conforme à laHashable
et si le type de système fonctionne comme prévu, il devrait accepter quoi que ce soit conforme àHashable
(class
,struct
etenum)
- J'ai pris la liberté de cross-posting pour relier à cette question sur un autre post sur le Dev Apple forums et répondre à cette question ici: devforums.apple.com/message/1045616 .
- Utilisation NSMutableDictionary
Vous devez vous connecter pour publier un commentaire.
Swift 3 mise à jour
Vous pouvez maintenant utiliser
AnyHashable
qui est un type effacé hashable valeur, créé exactement pour les scénarios comme ceci:var dict = Dictionary<AnyHashable, Int>()
Je crois que, en tant que de Swift 1.2, vous pouvez utiliser un ObjectIdentifier struct pour cela. Il met en œuvre Hashable (et donc Equatable) ainsi que Comparable. Vous pouvez l'utiliser pour envelopper toute instance de classe. Je devine que la mise en œuvre utilise le enveloppés de l'objet sous-jacent de l'adresse de l'hashValue, ainsi qu'au sein de l'opérateur==.
J'ai pris la liberté de cross-posting pour relier à cette question sur un autre post sur le Dev Apple forums, et cette question est la réponse ici.
Modifier
Cette réponse à partir du lien ci-dessus fonctionne en 6.1 et plus:
Dictionnaire est
struct Dictionary<Key : Hashable, Value>...
Ce qui signifie que la Valeur pourrait être tout ce que vous voulez, et pourrait être n'importe quel type que vous voulez, mais la Clé doit être conforme à
Hashable
protocole.Vous ne pouvez pas créer de
Dictionary<Any, Int>()
ouDictionary<AnyObject, Int>()
, parce queAny
etAnyObject
ne peux pas garantir qu'une telle Clé est conformeHashable
Vous ne pouvez pas créer de
Dictionary<Hashable, Int>()
, parce queHashable
n'est pas un type qu'il est juste protocole décrivant les types nécessaire.Mais vous vous êtes trompé dans la terminologie. Erreur d'origine est
type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
Cela signifie que Xcode en supposant que "Hashable" comme certains le type de, mais il n'y a pas ce type. Et Xcode le traiter comme une sorte de vide type, qui, évidemment, ne se conforme pas à tout protocole à tous (dans ce cas, il n'est pas conforme à hérité protocole
Equatable
)Quelque chose de semblable se passe avec
KeyType
.Vous voir
existing type
.protocol<Hashable, Equatable>
n'est pas un type de protocole, de sorte Xcode nouveau vous dit quetype 'KeyType' does not conform to protocol 'Equatable'
Vous pouvez utiliser
Dictionary<NSObject, Int>
juste, parce queNSObject
conformeHashable
protocole.Swift est le typage fort de la langue et vous ne pouvez pas faire certaines choses comme
creating Dictionary that can hold anything in Key
. Effectivement dictionnaire prend déjà en charge tout peut retenir la Clé, ce qui est conformeHashable
. Mais puisque vous devez spécifier classe particulière, vous ne pouvez pas faire ce natif Swift classes, car il n'y a pas une telle classe de maître de Swift comme en Objective-C, ce qui est conforme air pourrait être conformes (avec l'aide d'extensions) pourHashable
Bien sûr, vous pouvez utiliser un wrapper comme
chrisco
suggéré. Mais je ne peux vraiment pas imaginer pourquoi vous en avez besoin. Il est grand que vous avez taper fort dans Swift de sorte que vous n'avez pas besoin de s'inquiéter à propos des types de coulée comme vous l'avez fait en Objective-CHashable
est juste un protocole de sorte que vous ne pouvez pas spécifier directement comme un type pour leKey
valeur. Ce que vous avez vraiment besoin est une façon d'exprimer "tout type de T tels que T implémenteHashable
. Ceci est géré par des contraintes de type rapide:Ce code compile.
Autant que je sache, vous ne pouvez utiliser que les contraintes de type générique de fonctions et de classes.
Hashable
directement comme un type de la Clé? Je peux le faire pour la valeur. et mon but est de créer un dictionnaire de clé peut êtreInt
etString
et rien de se conformer àHashable
NSDictioanry
peut faire, le type de clé juste besoin de se conformerNSCopying
qui peut êtreNSString
ouNSNumber
Ce n'est pas exactement la réponse à la question, mais a m'a aidé.
La réponse générale serait de mettre en œuvre Hashable pour tous vos types, mais cela peut être difficile pour les Protocoles car Hashable s'étend Equatable et Equatable utilise l'Auto qui impose de sévères restrictions sur ce qu'est un protocole peut être utilisé pour.
Au lieu de mettre en œuvre Imprimable et puis faire:
La mise en œuvre de la description doit être quelque chose comme:
Pas une réponse parfaite, mais le meilleur que j'ai pour l'instant 🙁
Cela ne répond pas à l'OP de la question, mais qui est un peu lié, et espérons-le, peut être utile dans certaines situations. Supposons que ce que vous voulez vraiment, c'est ceci:
Mais Swift est de vous dire "Type" de Toute.Type' n'est pas conforme au protocole Hashable".
La plupart des réponses ci-dessus sont à propos de l'utilisation des instances de l'objet comme une clé de dictionnaire, à ne pas utiliser le type de l'objet. (Ce qui est assez juste, c'est ce que l'OP a demandé à propos.) C'était la réponse par Howard Lovatt qui m'a conduit à une solution viable.
EDIT:
Si les classes sont définies dans les différents modules, et peut que les noms de classe si vous négligez le nom du module, puis substitut "de la Chaîne(à l'image:" pour "String(décrit:", à la fois lors de la construction du dictionnaire et quand on fait de la recherche.
Vous pouvez utiliser le nom de la classe comme un Hashable, par exemple:
Voir Comment puis-je imprimer le type ou la classe d'une variable dans Swift? pour savoir comment vous pouvez obtenir le nom de la classe.