2017-07-08 3 views
0

Gibt es eine Problemumgehung, um ein Wörterbuch mit Optional Schlüsseln zu erstellen? Ich weiß, dass eine angemessene Lösung dafür die Umsetzung von Conditional Conformances erfordert, aber habe ich vorher irgendwelche Optionen?Wörterbuch der optionalen Tasten

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

Sind Sie sicher, dass Sie das wollen? Definitionsgemäß gibt eine Taste 'nil' an * no value * an und der Typ kann nicht in 'NSDictionary' überbrückt werden, da der Typ Foundation nur nicht optionale Typen als Schlüsselwert ** und ** unterstützt. – vadian

+0

@vadian Ja, ich brauche keine Vogelbeobachtung nach 'NSDictionary'. Hier ist mein Anwendungsfall: Ich baue eine Klassenhierarchie der Klassen in der Ziel-C-Laufzeit. Mit diesem Diktat werden Klassen einem Array ihrer Unterklassen zugeordnet. Wurzelklassen haben eine "nil" Superklasse, wie sie von 'class_getSuperclass' gegeben wird. – Alexander

+0

@vadian Es könnte zu 'NSDictionary' überbrückt werden, da' nil' zu 'NSNull' überbrückt wird. – Hamish

Antwort

1

Hier ist eine Abhilfe, die ich gefunden: Erstellen Sie ein neues 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 
    } 
} 

Und dann kann man es wie so verwenden:

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

Persönlich würde ich nur den Wrappertyp eine "struct" mit einem exposed 'Wrapped?' '' base''-Eigenschaft, und dann verweisen Sie einfach auf 'key.base', wenn Sie auf den optionalen Wert zugreifen müssen. Weil 'Optional' mit einer Menge von eingebrannten Sprachmerkmalen kommt, die nicht auf dem Wrapper selbst repliziert werden können (optionale Verkettung, optionale Bindung, implizite Werbung, Zuckermuster, ...), so dass IMO eine klare Unterscheidung zwischen dem Wrapper macht und der zugrunde liegende Wert gibt eine konsistentere Schnittstelle. – Hamish

+0

@Hamish Guter Punkt. Wie Sie sehen können, habe ich beim Hinzufügen von Map und Flatmap ausgelassen. Ich denke, der Zugriff auf den Wert wäre einfacher, und ich kann ihn auch direkt speichern. Weißt du, mir gefiel irgendwie, wie man die bedingte Bindung für jeden Typ mit keinen/einigen Fällen verwenden könnte – Alexander

Verwandte Themen