通过哈希值访问枚举值?

时间:2014-09-27 17:35:29

标签: swift enums

枚举有一个名为' hashValue'这是它在枚举中的索引。

现在我的问题是,是否可以通过使用数字来访问其值?例如:let variable:AnEnum = 0

6 个答案:

答案 0 :(得分:14)

如果要将枚举值映射到整数,则应直接使用原始值。例如(来自Swift Programming Language: Enumerations):

enum Planet: Int {
    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}

let possiblePlanet = Planet(rawValue: 7)

我不相信有任何文档承诺枚举的hashValue特别是任何东西(如果你有链接,我会非常感兴趣)。如果没有,你应明确指定原始值。

答案 1 :(得分:10)

enum Opponent: String {
   case Player
   case Computer

   static func fromHashValue(hashValue: Int) -> Opponent {
       if hashValue == 0 {
           return .Player
       } else {
           return .Computer
       }
   }

}

<强>解释

由于无法从hashValue中获取枚举值,因此必须手动执行。它不漂亮,但它的工作原理。您实际上创建了一个函数,允许您传入所需值的索引并手动将该枚举值返回给调用者。这可能会因为大量案例的枚举而变得令人讨厌,但它对我来说就像是一种魅力。

答案 2 :(得分:0)

Swift 4.2(基于@Stephen Paul的先前回答)

此答案使用switch而不是if / else子句。并返回可选值,因为您不保证所提供的哈希将匹配。

enum CellType:String{
    case primary,secondary,tierary
    /**
     * NOTE: Since there is no way to get back an enum value from its hashValue, you have to do it manually.
     * EXAMPLE: CellType.fromHashValue(hashValue: 1)?.rawValue//primary
     */
    static func fromHashValue(hashValue: Int) -> CellType? {
        switch hashValue {
        case 0:
            return .primary
        case 1:
            return .secondary
        case 2:
            return .tierary
        default:
            return nil
        }
    }
}

答案 3 :(得分:0)

您的要求是运行以下代码行,其中0是枚举变量的hashValue(请注意,从Xcode 10开始,0永远不是有效的hashValue。 ..):

let variable:AnEnum = 0

只需将枚举设置为ExpressibleByIntegerLiteralCaseIterable即可完成

extension AnEnum: CaseIterable, ExpressibleByIntegerLiteral {
    typealias IntegerLiteralType = Int

    public init(integerLiteral value: IntegerLiteralType) {
        self = AnEnum.allCases.first { $0.hashValue == value }!
    }
}

CaseIterable协议在Swift 4.2中是本机可用的,您可以使用https://stackoverflow.com/a/49588446/1033581中的代码针对较早的swift版本(Swift 3.x,4.x)自己实现。

答案 4 :(得分:0)

实际上,在Swift 4.2中,hashValue不再是enum内部的索引。

编辑:刚刚找到了一种更安全的方法来实现这一目标。您可以使用CaseIterable(Swift 4.2)并在allCases集合中选择所需的大小写。

enum Foo: CaseIterable {
  case bar
  case baz

  init?(withIndex index: Int) {
    guard Foo.allCases.indices ~= index else { return nil }
    self = Foo.allCases[index]
  }
}

Foo(withIndex: 0) // bar
Foo(withIndex: 1) // baz
Foo(withIndex: 2) // nil

注意:,我在这里留下了这个小技巧,因为玩不安全的指针很有趣,但是,请请勿使用此方法创建带有指数。 它依赖于Swift内存表示形式,该表示形式可能会发生更改,恕不另行通知,而且由于使用错误的索引会导致运行时错误,因此这确实是不安全的。

话虽这么说,在Swift中,用原始存储器中的Int代表了一个案例。因此,您可以使用它使用不安全的指针来构建案例。

enum Foo {
  case bar
  case baz

  init(withIndex index: UInt8) {
    var temp: Foo = .bar
    withUnsafeMutablePointer(to: &temp) { pointer in
      let ptr = UnsafeMutableRawPointer(pointer).bindMemory(to: UInt8.self, capacity: 1)
      ptr.pointee = index
    }

    self = temp
  }
}

Foo(withIndex: 0) // bar
Foo(withIndex: 1) // baz
Foo(withIndex: 2) // runtime error !

答案 5 :(得分:0)

iOS 4的Swift 4:

只需通过显式设置原始类型(如下面的示例中的Int)即可使枚举:

enum OrderStatus: Int {
    case noOrder
    case orderInProgress
    case orderCompleted
    case orderCancelled
}

用法:

var orderStatus: OrderStatus = .noOrder // default value 

print(orderStatus.rawValue) // it will print 0

orderStatus = .orderCompleted
print(orderStatus.rawValue) // it will print 2