2016-05-16 18 views
2

Ich mag würde eine Enumeration mit zwei Fällen haben, mit einem Hashable zugehörigen Typ jeweils Hashable entsprechen, etwa so:Hashable Enum in Swift

enum WordOrNumber { 
    case Word(String) 
    case Number(Int) 
} 

Die erste Idee, die ich für Hashing hatte, war die folgende:

extension WordOrNumber: Hashable { 
    var hashValue: Int { 
     switch self { 
      case let .Word(word): 
       return word.hashValue & ~1 // ends in 0 
      case let .Number(number): 
       return number.hashValue | 1 // ends in 1 
     } 
    } 
} 

Worüber ich nicht sicher bin, ist, wie dies mit Eimern in Swift's Dictionary und Set-Implementierungen interagieren wird.

Ist es besser, die beiden Fälle durch das LSB oder MSB oder etwas in der Mitte zu unterscheiden?

Ich nehme an, dass es keinen Unterschied macht, die Hash-Werte von eins zu verschieben und dann 1 hinzuzufügen, oder nicht, aber ich wäre interessiert zu wissen, ob dies nicht der Fall ist.

EDIT: Ich habe gerade getestet, und es sieht aus wie der Hash-Wert eines Int ist der Wert selbst. Dies ist offensichtlich ein Problem, da Sie oft hintereinander kommen, wie in einem Enum Bla: Int {}. (?) Also meine neue und verbesserte HashValue ist:

extension WordOrNumber: Hashable { 
    var hashValue: Int { 
     switch self { 
      case let .Word(word): // ends in 0 
       return word.hashValue << 1 
      case let .Number(number): // ends in 1 
       return number.hashValue << 1 &+ 1 
     } 
    } 
} 

Die obige Frage zu LSB und MSB noch steht.

+0

Es ist eigentlich nicht notwendig, diese beiden Fälle zu unterscheiden. Was willst du damit erreichen? – Sulthan

+0

Ich bin mir nicht sicher, was du meinst? Sicherlich könnte es einen Konflikt in den hashValues ​​von String und Int geben, wo .Number (x) == .Word (y), was ist problematisch? –

+0

Warum sollte das problematisch sein? Hash-Funktionen sollen keine eindeutigen Ergebnisse liefern, was wirklich wichtig ist, ist die Definition von Gleichheit ('Equatable', Funktion' == '). Ich würde auch annehmen, dass sowohl 'Set' als auch' Dictionary' eine sekundäre Hash-Funktion verwenden. – Sulthan

Antwort

0

Mit so etwas wie:

extension WordOrNumber: Hashable { 
    var hashValue: Int { 
     switch self { 
     case .Word(let value): 
      return value.hashValue 
     case .Number(let value): 
      return value.hashValue 
     } 
    } 

    static func ==(lhs: WordOrNumber, rhs: WordOrNumber) -> Bool { 
     switch (lhs, rhs) { 
     case (.Word(let lhsValue), .Word(let rhsValue)): 
      return lhsValue == rhsValue 
     case (.Number(let lhsValue), .Number(let rhsValue)): 
      return lhsValue == rhsValue 
     default: 
      return false 
     } 
    } 
} 

... sollte genügen.