2017-07-08 4 views
0

Existe-t-il une solution de contournement pour créer un dictionnaire avec les clés Optional? Je sais qu'une solution appropriée pour cela nécessiterait la mise en œuvre de conformations conditionnelles, mais ai-je des options avant cela?Dictionnaire des clés optionnelles

let dict: [Int?: Int] = [nil: 1] 
// ERROR: type 'Int?' does not conform to protocol 'Hashable' 
+0

Êtes-vous sûr de vouloir ça? Par définition, une clé 'nil' indique * no value * et le type ne peut pas être lié à' NSDictionary' car le type Foundation ne prend en charge que les types non optionnels comme clé ** et ** value. – vadian

+0

@vadian Oui, je n'ai pas besoin de birding pour 'NSDictionary'. Voici mon cas d'utilisation: Je construis une hiérarchie de classe des classes dans le runtime de l'objectif C. Cette dict va mapper les classes à un tableau de leurs sous-classes. Les classes racines ont une superclasse "nil", donnée par 'class_getSuperclass'. – Alexander

+0

@vadian Il pourrait être relié à 'NSDictionary', car' nil' sera relié à 'NSNull'. – Hamish

Répondre

1

Voici une solution de contournement j'ai trouvé: Créer une nouvelle HashableOptionalenum:

enum HashableOptional<Wrapped: Hashable> { 
    case none 
    case some(Wrapped) 

    public init(_ some: Wrapped) { 
     self = .some(some) 
    } 

    public init(_ optional: Wrapped?) { 
     self = optional.map{ .some($0) } ?? .none 
    } 

    public var value: Wrapped? { 
     switch self { 
      case .none: return nil 
      case .some(let wrapped): return wrapped 
     } 
    } 
} 

extension HashableOptional: Equatable { 
    static func ==(lhs: HashableOptional, rhs: HashableOptional) -> Bool { 
     switch (lhs, rhs) { 
      case (.none, .none): return true 
      case (.some(let a), .some(let b)): return a == b 
      default: return false 
     } 
    } 
} 

extension HashableOptional: Hashable { 
    var hashValue: Int { 
     switch self { 
      case .none: return 0 
      case .some(let wrapped): return wrapped.hashValue 
     } 
    } 
} 

extension HashableOptional: ExpressibleByNilLiteral { 
    public init(nilLiteral:()) { 
     self = .none 
    } 
} 

Et vous pouvez alors l'utiliser comme ceci:

let dict: [HashableOptional<Int>: Int] = [nil: 1] 
+0

Personnellement, je voudrais juste faire du type wrapper un 'struct' avec un Exposé 'Wrapped?' 'base' propriété, puis il suffit de se référer à' key.base' lorsque vous avez besoin d'accéder à la valeur facultative. Parce que 'Optional' est livré avec de nombreuses fonctionnalités de langage qui ne peuvent pas être répliquées sur l'encapsuleur lui-même (chaînage facultatif, liaison facultative, promotion implicite, modèles de sucre, ...), afin que l'OMI fasse une distinction claire entre l'encapsuleur et la valeur sous-jacente donne une interface plus cohérente. – Hamish

+0

@Hamish Bon point. Comme vous pouvez le voir, j'ai sauté sur l'ajout de la carte et flatmap. Je pense que l'accès à la valeur serait plus facile, et je pourrais tout aussi bien le stocker directement. Vous savez, j'ai un peu aimé comment vous pouvez utiliser une liaison conditionnelle sur n'importe quel type avec aucun/certains cas – Alexander