如何确定Swift enum中的案例数?

(我希望避免手动枚举所有值,或者如果可能的话使用旧的“enum_count技巧”。)


当前回答

扩展Matthieu Riegler的回答,这是一个Swift 3的解决方案,不需要使用泛型,可以很容易地使用枚举类型EnumType.elementsCount调用:

extension RawRepresentable where Self: Hashable {

    // Returns the number of elements in a RawRepresentable data structure
    static var elementsCount: Int {
        var i = 1
        while (withUnsafePointer(to: &i, {
            return $0.withMemoryRebound(to: self, capacity: 1, { return 
                   $0.pointee })
        }).hashValue != 0) {
            i += 1
        }
        return i
}

其他回答

我写了一个简单的扩展,它给所有枚举的原始值是整数一个count属性:

extension RawRepresentable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

不幸的是,它给了计数属性OptionSetType,它不会正常工作,所以这里是另一个版本,需要显式符合CaseCountable协议的任何枚举的情况下,你想要计数:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

它与Tom Pelaia发布的方法非常相似,但适用于所有整数类型。

Swift 3版本使用Int类型枚举:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
    static var count: RawValue {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) { i += 1 }
        return i
    }
}

演职员名单:本文基于bzz和Nate Cook的回答。

泛型IntegerType(在Swift 3中重命名为Integer)不受支持,因为它是一个严重碎片化的泛型类型,缺少很多函数。继任者在Swift 3中不再可用。

注意代码指挥官对Nate Cooks回答的注释仍然有效:

虽然这很好,因为您不需要硬编码一个值,但这会 每次调用枚举值时实例化每个枚举值。这是O(n) 而不是O(1)

据我所知,由于泛型类型中不支持静态存储属性,因此在使用此作为协议扩展时(并且没有像Nate Cook那样在每个枚举中实现)目前没有解决方案。

无论如何,对于小枚举,这应该不是问题。一个典型的用例就是section。如Zorayr所提到的UITableViews。

为什么要把事情搞得这么复杂?Int enum最简单的计数器是添加:

病例数

最后。和…维奥拉,现在你有计数了,又快又简单

大家好,单元测试呢?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

    var max: Int = 0
    while let _ = Test(rawValue: max) { max += 1 }

    XCTAssert(max == Test.count)
}

这与安东尼奥的解决方案相结合:

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}

在主代码中给你O(1),加上如果有人添加了enum case 5并且没有更新count的实现,你会得到一个失败的测试。

这种函数能够返回枚举的计数。

斯威夫特2:

func enumCount<T: Hashable>(_: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
        i += 1
    }
    return i
}

斯威夫特3:

func enumCount<T: Hashable>(_: T.Type) -> Int {
   var i = 1
   while (withUnsafePointer(to: &i, {
      return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
   }).hashValue != 0) {
      i += 1
   }
      return i
   }