如何确定Swift enum中的案例数?
(我希望避免手动枚举所有值,或者如果可能的话使用旧的“enum_count技巧”。)
如何确定Swift enum中的案例数?
(我希望避免手动枚举所有值,或者如果可能的话使用旧的“enum_count技巧”。)
当前回答
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().enumCount
}
}
enum E {
case A
case B
case C
}
E.enumCases() // [A, B, C]
E.enumCount // 3
但是在非enum类型上使用时要小心。一些变通办法可以是:
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
guard sizeof(T) == 1 else {
return nil
}
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().count
}
}
enum E {
case A
case B
case C
}
Bool.enumCases() // [false, true]
Bool.enumCount // 2
String.enumCases() // []
String.enumCount // 0
Int.enumCases() // []
Int.enumCount // 0
E.enumCases() // [A, B, C]
E.enumCount // 4
其他回答
如果你不想在最后一个枚举中创建你的代码,你可以在枚举中创建这个函数。
func getNumberOfItems() -> Int {
var i:Int = 0
var exit:Bool = false
while !exit {
if let menuIndex = MenuIndex(rawValue: i) {
i++
}else{
exit = true
}
}
return i
}
或者你可以在枚举之外定义_count,并静态地附加它:
let _count: Int = {
var max: Int = 0
while let _ = EnumName(rawValue: max) { max += 1 }
return max
}()
enum EnumName: Int {
case val0 = 0
case val1
static let count = _count
}
这样,不管你创建了多少个枚举,它只会被创建一次。
(如果是静态的,就删除这个答案)
以下方法来自CoreKit,与其他人建议的答案相似。这适用于Swift 4。
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
static var allValues: [Self] { get }
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
public static var allValues: [Self] {
return Array(self.cases())
}
}
enum Weekdays: String, EnumCollection {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
然后你只需要调用weekdays。allvalues。count。
我有一篇博客文章详细介绍了这一点,但只要你的枚举的原始类型是一个整数,你可以这样添加一个计数:
enum Reindeer: Int {
case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
case Rudolph
static let count: Int = {
var max: Int = 0
while let _ = Reindeer(rawValue: max) { max += 1 }
return max
}()
}
扩展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
}