How to enumerate an enum with String type?
1 2 3 4 5 6 | enum Suit: String { case spades ="?" case hearts ="?" case diamonds ="?" case clubs ="?" } |
例如,我如何执行以下操作:
1 2 3 4 | for suit in Suit { // do something with suit print(suit.rawValue) } |
结果示例:
1 2 3 4 | ? ? ? ? |
本帖与此相关:https://www.swift-studies.com/blog/2014/6/10/enumering-enums-in-swift
基本上,建议的解决方案是
1 2 3 4 5 6 7 8 9 | enum ProductCategory : String { case Washers ="washers", Dryers ="dryers", Toasters ="toasters" static let allValues = [Washers, Dryers, Toasters] } for category in ProductCategory.allValues{ //Do something } |
我做了一个实用函数
以下是示例用法:
1 2 3 4 5 6 7 8 9 10 | enum Suit:String { case Spades ="?" case Hearts ="?" case Diamonds ="?" case Clubs ="?" } for f in iterateEnum(Suit) { println(f.rawValue) } |
输出:
1 2 3 4 | ? ? ? ? |
但是,这只是为了调试或测试:这依赖于几个未记录的当前(swift1.1)编译器行为。因此,使用它的风险由您自己承担:)
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | func iterateEnum<T: Hashable>(_: T.Type) -> GeneratorOf<T> { var cast: (Int -> T)! switch sizeof(T) { case 0: return GeneratorOf(GeneratorOfOne(unsafeBitCast((), T.self))) case 1: cast = { unsafeBitCast(UInt8(truncatingBitPattern: $0), T.self) } case 2: cast = { unsafeBitCast(UInt16(truncatingBitPattern: $0), T.self) } case 4: cast = { unsafeBitCast(UInt32(truncatingBitPattern: $0), T.self) } case 8: cast = { unsafeBitCast(UInt64($0), T.self) } default: fatalError("cannot be here") } var i = 0 return GeneratorOf { let next = cast(i) return next.hashValue == i++ ? next : nil } } |
基本理念是:
enum 的记忆表示法(不包括enum 及其相关类型)只是一种病例索引,当病例数为2...256 时,它与UInt8 相同,当257...65536 时,它与UInt16 等相同。因此,它可以是对应的无符号整数类型中的unsafeBitcast 。- 枚举值的
.hashValue 与案例的索引相同。 - 从无效索引中发出的枚举值的
.hashValue 是0 。
补充:
为Swift2进行了修订,并从@Kametrixom的答案中实现了铸造理念。
1 2 3 4 5 6 7 | func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> { var i = 0 return anyGenerator { let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory } return next.hashValue == i++ ? next : nil } } |
补充:修改为swift3
1 2 3 4 5 6 7 8 9 10 11 | func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> { var i = 0 return AnyIterator { let next = withUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } } if next.hashValue != i { return nil } i += 1 return next } } |
补充:修改为swift3.0.1
1 2 3 4 5 6 7 8 9 | func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> { var i = 0 return AnyIterator { let next = withUnsafeBytes(of: &i) { $0.load(as: T.self) } if next.hashValue != i { return nil } i += 1 return next } } |
斯威夫特4.2 +
从Swift 4.2(Xcode 10)开始,只需添加与
1 | extension Suit: CaseIterable {} |
然后将打印所有可能的值:
1 2 3 | Suit.allCases.forEach { print($0.rawValue) } |
与早期的swift版本(3.x和4.x)兼容
只需模拟swift 4.2的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #if !swift(>=4.2) public protocol CaseIterable { associatedtype AllCases: Collection where AllCases.Element == Self static var allCases: AllCases { get } } extension CaseIterable where Self: Hashable { static var allCases: [Self] { return [Self](AnySequence { () -> AnyIterator<Self> in var raw = 0 var first: Self? return AnyIterator { let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) } if raw == 0 { first = current } else if current == first { return nil } raw += 1 return current } }) } } #endif |
其他的解决方案也有效,但它们都假设了可能的等级和诉讼数量,或者第一个和最后一个等级可能是什么。诚然,在可预见的未来,一副牌的布局可能不会有太大变化。然而,一般来说,编写尽可能少做假设的代码比较整洁。我的解决方案:
我已经向suit枚举添加了一个原始类型,因此可以使用suit(rawvalue:)访问suit cases:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | enum Suit: Int { case Spades = 1 case Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return"spades" case .Hearts: return"hearts" case .Diamonds: return"diamonds" case .Clubs: return"clubs" } } func color() -> String { switch self { case .Spades: return"black" case .Clubs: return"black" case .Diamonds: return"red" case .Hearts: return"red" } } } enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return"ace" case .Jack: return"jack" case .Queen: return"queen" case .King: return"king" default: return String(self.rawValue) } } } |
在card的createDeck()方法的实现下面。init(rawvalue:)是一个可失败的初始值设定项,并返回一个可选的。通过拆解和检查这两个while语句中的值,无需假设排名或诉讼案例的数量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return"The \(rank.simpleDescription()) of \(suit.simpleDescription())" } func createDeck() -> [Card] { var n = 1 var deck = [Card]() while let rank = Rank(rawValue: n) { var m = 1 while let suit = Suit(rawValue: m) { deck.append(Card(rank: rank, suit: suit)) m += 1 } n += 1 } return deck } } |
以下是如何调用CreateDeck方法:
1 2 | let card = Card(rank: Rank.Ace, suit: Suit.Clubs) let deck = card.createDeck() |
第二个真正有效的答案
因此,我在字节和位中发现了一些问题,并创建了一个扩展(后来我发现它的工作原理与@rintaro的答案非常相似)。它可以这样使用:
1 2 3 4 5 | enum E : EnumCollection { case A, B, C } Array(E.cases()) // [A, B, C] |
值得注意的是,它可以用于任何枚举(没有关联的值)。请注意,这对没有案例的枚举不起作用。
免责声明与@rintaro的答案一样,此代码使用枚举的基础表示形式。这种表示法没有记录在案,将来可能会改变,这会破坏它->我不建议在生产中使用它。
代码(swift 2.2,xcode 7.3.1,不在xcode 10上工作)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | protocol EnumCollection : Hashable {} extension EnumCollection { static func cases() -> AnySequence<Self> { typealias S = Self return AnySequence { () -> AnyGenerator<S> in var raw = 0 return AnyGenerator { let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory } guard current.hashValue == raw else { return nil } raw += 1 return current } } } } |
代码(swift 3,xcode 8.1,不在xcode 10上工作)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | protocol EnumCollection : Hashable {} extension EnumCollection { static func cases() -> AnySequence<Self> { typealias S = Self return AnySequence { () -> AnyIterator<S> in var raw = 0 return AnyIterator { let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } } guard current.hashValue == raw else { return nil } raw += 1 return current } } } } |
(我不知道为什么我需要
(我对这个答案做了很大修改,看看以前版本的编辑)
您可以通过实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | enum Rank: Int, ForwardIndexType { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King // ... other functions // Option 1 - Figure it out by hand func successor() -> Rank { switch self { case .Ace: return .Two case .Two: return .Three // ... etc. default: return .King } } // Option 2 - Define an operator! func successor() -> Rank { return self + 1 } } // NOTE: The operator is defined OUTSIDE the class func + (left: Rank, right: Int) -> Rank { // I'm using to/from raw here, but again, you can use a case statement // or whatever else you can think of return left == .King ? .King : Rank(rawValue: left.rawValue + right)! } |
在打开或关闭的范围内迭代(
1 2 3 4 | // Under the covers, successor(Rank.King) and successor(Rank.Ace) are called to establish limits for r in Rank.Ace...Rank.King { // Do something useful } |
原则上,可以这样做,前提是不为枚举的情况使用原始值分配:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | enum RankEnum: Int { case Ace case One case Two } class RankEnumGenerator : Generator { var i = 0 typealias Element = RankEnum func next() -> Element? { let r = RankEnum.fromRaw(i) i += 1 return r } } extension RankEnum { static func enumerate() -> SequenceOf<RankEnum> { return SequenceOf<RankEnum>({ RankEnumGenerator() }) } } for r in RankEnum.enumerate() { println("\(r.toRaw())") } |
这个问题现在容易多了。这是我的Swift 4.2解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | enum Suit: Int, CaseIterable { case None case Spade, Heart, Diamond, Club static let allNonNullCases = Suit.allCases[Spade.rawValue...] } enum Rank: Int, CaseIterable { case Joker case Two, Three, Four, Five, Six, Seven, Eight case Nine, Ten, Jack, Queen, King, Ace static let allNonNullCases = Rank.allCases[Two.rawValue...] } func makeDeck(withJoker: Bool = false) -> [Card] { var deck = [Card]() for suit in Suit.allNonNullCases { for rank in Rank.allNonNullCases { deck.append(Card(suit: suit, rank: rank)) } } if withJoker { deck.append(Card(suit: .None, rank: .Joker)) } return deck } |
前4.2
我喜欢这个解决方案,在找到这个页面后我把它放在一起:斯威夫特列表理解
它使用int raws而不是字符串,但它避免键入两次,允许自定义范围,并且不硬编码原始值。
这是我最初的解决方案的Swift 4版本,但请参阅上面的4.2改进。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | enum Suit: Int { case None case Spade, Heart, Diamond, Club static let allRawValues = Suit.Spade.rawValue...Suit.Club.rawValue static let allCases = Array(allRawValues.map{ Suit(rawValue: $0)! }) } enum Rank: Int { case Joker case Two, Three, Four, Five, Six case Seven, Eight, Nine, Ten case Jack, Queen, King, Ace static let allRawValues = Rank.Two.rawValue...Rank.Ace.rawValue static let allCases = Array(allRawValues.map{ Rank(rawValue: $0)! }) } func makeDeck(withJoker: Bool = false) -> [Card] { var deck = [Card]() for suit in Suit.allCases { for rank in Rank.allCases { deck.append(Card(suit: suit, rank: rank)) } } if withJoker { deck.append(Card(suit: .None, rank: .Joker)) } return deck } |
如果给枚举一个原始int值,它将使循环更容易。
例如,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | enum Suit: Int, CustomStringConvertible { case Spades, Hearts, Diamonds, Clubs var description: String { switch self { case .Spades: return"Spades" case .Hearts: return"Hearts" case .Diamonds: return"Diamonds" case .Clubs: return"Clubs" } } static func enumerate() -> AnyGenerator<Suit> { var nextIndex = Spades.rawValue return anyGenerator { Suit(rawValue: nextIndex++) } } } // You can now use it like this: for suit in Suit.enumerate() { suit.description } // or like this: let allSuits: [Suit] = Array(Suit.enumerate()) |
然而,这看起来是一个相当常见的模式,如果我们可以通过简单地符合协议使任何枚举类型可枚举,这不是很好吗?有了Swift2.0和协议扩展,现在我们可以了!
只需将此添加到项目中:
1 2 3 4 5 6 7 8 9 10 11 | protocol EnumerableEnum { init?(rawValue: Int) static func firstValue() -> Int } extension EnumerableEnum { static func enumerate() -> AnyGenerator<Self> { var nextIndex = firstRawValue() return anyGenerator { Self(rawValue: nextIndex++) } } static func firstRawValue() -> Int { return 0 } } |
现在,无论何时创建枚举(只要它具有int原始值),都可以通过符合协议使其可枚举:
1 2 3 4 5 | enum Rank: Int, EnumerableEnum { case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King } // ... for rank in Rank.enumerate() { ... } |
如果枚举值不是以
1 2 3 4 5 6 | enum DeckColor: Int, EnumerableEnum { case Red = 10, Blue, Black static func firstRawValue() -> Int { return Red.rawValue } } // ... let colors = Array(DeckColor.enumerate()) |
最终的诉讼类别,包括用更标准的customstringconvertible协议替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | enum Suit: Int, CustomStringConvertible, EnumerableEnum { case Spades, Hearts, Diamonds, Clubs var description: String { switch self { case .Spades: return"Spades" case .Hearts: return"Hearts" case .Diamonds: return"Diamonds" case .Clubs: return"Clubs" } } } // ... for suit in Suit.enumerate() { print(suit.description) } |
编辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | protocol EnumerableEnum { init?(rawValue: Int) static func firstRawValue() -> Int } extension EnumerableEnum { static func enumerate() -> AnyIterator<Self> { var nextIndex = firstRawValue() let iterator: AnyIterator<Self> = AnyIterator { defer { nextIndex = nextIndex + 1 } return Self(rawValue: nextIndex) } return iterator } static func firstRawValue() -> Int { return 0 } } |
更新至Swift 2.2+
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> { var i = 0 return AnyGenerator { let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory } if next.hashValue == i { i += 1 return next } else { return nil } } } |
它将代码更新为swift 2.2表格@kametrixom的答案
对于Swift 3.0+(非常感谢@Philip)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> { var i = 0 return AnyIterator { let next = withUnsafePointer(&i) { UnsafePointer<T>($0).pointee } if next.hashValue == i { i += 1 return next } else { return nil } } } |
我发现自己在代码中做了很多。我最终找到了一种简单地符合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | protocol Iteratable {} extension RawRepresentable where Self: RawRepresentable { static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> { var i = 0 return AnyIterator { let next = withUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } } if next.hashValue != i { return nil } i += 1 return next } } } extension Iteratable where Self: RawRepresentable, Self: Hashable { static func hashValues() -> AnyIterator<Self> { return iterateEnum(self) } static func rawValues() -> [Self.RawValue] { return hashValues().map({$0.rawValue}) } } // Example enum Grocery: String, Iteratable { case Kroger ="kroger" case HEB ="h.e.b." case Randalls ="randalls" } let groceryHashes = Grocery.hashValues() // AnyIterator<Grocery> let groceryRawValues = Grocery.rawValues() // ["kroger","h.e.b.","randalls"] |
编辑:Swift Evolution Proposal SE-0194派生的枚举案例集合为这个问题提出了一个平庸的解决方案。我们在Swift 4.2和更新版本中看到它。该提案还指出了一些类似于这里已经提到过的一些解决方法,但可能会有趣地看到。
为了完整起见,我也会保留我原来的职位。
这是另一种基于@peymmankh答案的方法,适用于Swift 3。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public protocol EnumCollection : Hashable {} extension EnumCollection { public static func allValues() -> [Self] { typealias S = Self let retVal = AnySequence { () -> AnyIterator<S> in var raw = 0 return AnyIterator { let current = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } } guard current.hashValue == raw else { return nil } raw += 1 return current } } return [S](retVal) } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | enum Rank: Int { ... static let ranks = (Rank.Ace.rawValue ... Rank.King.rawValue).map{Rank(rawValue: $0)! } } enum Suit { ... static let suits = [Spades, Hearts, Diamonds, Clubs] } struct Card { ... static func fullDesk() -> [Card] { var desk: [Card] = [] for suit in Suit.suits { for rank in Rank.ranks { desk.append(Card(rank: rank,suit: suit)) } } return desk } } |
这个怎么样?
在swift 3中,当基础枚举具有rawvalue_s时,可以实现可跨接协议。其优点是,没有像其他一些建议中那样创建值数组,并且标准的swift"for i in…"语句工作正常,这使得语法更加良好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | //"Int" to get rawValue, and {Strideable} so we can iterate enum MyColorEnum : Int, Strideable { case Red case Green case Blue case Black //-------- required by {Strideable} typealias Stride = Int func advanced(by n:Stride) -> MyColorEnum { var next = self.rawValue + n if next > MyColorEnum.Black.rawValue { next = MyColorEnum.Black.rawValue } return MyColorEnum(rawValue: next)! } func distance(to other: MyColorEnum) -> Int { return other.rawValue - self.rawValue } //-------- just for printing func simpleDescription() -> String { switch self { case .Red: return"Red" case .Green: return"Green" case .Blue: return"Blue" case .Black: return"Black" } } } // this is how you use it: for i in MyColorEnum.Red ... MyColorEnum.Black { print("ENUM: \(i)") } |
这就是我最终要做的;我认为它在可读性和可维护性之间达到了正确的平衡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct Card { // ... static func deck() -> Card[] { var deck = Card[]() for rank in Rank.Ace.toRaw()...Rank.King.toRaw() { for suit in [Suit.Spades, .Hearts, .Clubs, .Diamonds] { let card = Card(rank: Rank.fromRaw(rank)!, suit: suit) deck.append(card) } } return deck } let deck = Card.deck() |
你可以这样列举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | enum Planet: String { case Mercury case Venus case Earth case Mars static var enumerate: [Planet] { var a: [Planet] = [] switch Planet.Mercury { case .Mercury: a.append(.Mercury); fallthrough case .Venus: a.append(.Venus); fallthrough case .Earth: a.append(.Earth); fallthrough case .Mars: a.append(.Mars) } return a } } Planet.enumerate // [Mercury, Venus, Earth, Mars] |
抱歉,我的回答是针对我如何在我需要做的事情中使用这篇文章的。对于那些偶然发现这个问题的人,寻找在枚举中查找案例的方法,这是一种方法(swift 2中的新方法):
编辑:小写camelcase现在是swift 3枚举值的标准
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // From apple docs: If the raw-value type is specified as String and you don’t assign values to the cases explicitly, each unassigned case is implicitly assigned a string with the same text as the name of that case. enum Theme: String { case white, blue, green, lavender, grey } func loadTheme(theme: String) { // this checks the string against the raw value of each enum case (note that the check could result in a nil value, since it's an optional, which is why we introduce the if/let block if let testTheme = Theme(rawValue: theme) { // testTheme is guaranteed to have an enum value at this point self.someOtherFunction(testTheme) } } |
对于那些对枚举枚举感到疑惑的人,本页中给出的包含包含所有枚举值数组的静态var/let的答案是正确的。苹果最新的TVOS示例代码包含了完全相同的技术。
也就是说,他们应该在语言中建立一个更方便的机制(苹果,你在听吗?)!
带Swift 4.2的Xcode 10
1 2 3 4 5 6 7 8 9 10 | enum Filter: String, CaseIterable { case salary ="Salary" case experience ="Experience" case technology ="Technology" case unutilized ="Unutilized" case unutilizedHV ="Unutilized High Value" static let allValues = Filter.allCases.map { $0.rawValue } } |
称之为
1 | print(Filter.allValues) |
印刷品:
["Salary","Experience","Technology","Unutilized","Unutilized High Value"]
旧版本代表
1 2 3 4 5 6 7 8 9 10 | enum Filter: Int { case salary case experience case technology case unutilized case unutilizedHV static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case static let allValues = allRawValues.map { Filter(rawValue: $0)!.rawValue } } |
这样称呼它:
1 | print(Filter.allValues) |
印刷品:
[0, 1, 2, 3, 4]
代表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | enum Filter: Int { case salary case experience case technology case unutilized case unutilizedHV static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case static let allValues = allRawValues.map { Filter(rawValue: $0)!.description } } extension Filter: CustomStringConvertible { var description: String { switch self { case .salary: return"Salary" case .experience: return"Experience" case .technology: return"Technology" case .unutilized: return"Unutilized" case .unutilizedHV: return"Unutilized High Value" } } } |
称之为
1 | print(Filter.allValues) |
印刷品:
["Salary","Experience","Technology","Unutilized","Unutilized High Value"]
实验是:实验
在卡片中添加一种方法,可以创建一副完整的卡片,其中每一张卡片都是等级和套装的组合。
因此,在不修改或增强给定代码的情况下,除了添加方法(并且不使用尚未教授过的内容),我提出了以下解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return"The \(rank.simpleDescription()) of \(suit.simpleDescription())" } func createDeck() -> [Card] { var deck: [Card] = [] for rank in Rank.Ace.rawValue...Rank.King.rawValue { for suit in Suit.Spades.rawValue...Suit.Clubs.rawValue { let card = Card(rank: Rank(rawValue: rank)!, suit: Suit(rawValue: suit)!) //println(card.simpleDescription()) deck += [card] } } return deck } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription() let deck = threeOfSpades.createDeck() |
这看起来像是一个黑客,但是如果你使用原始值,你可以这样做。
1 2 3 4 5 6 7 8 9 | enum Suit: Int { case Spades = 0, Hearts, Diamonds, Clubs ... } var suitIndex = 0 while var suit = Suit.fromRaw(suitIndex++) { ... } |
枚举具有toraw()和fromraw()方法,因此如果原始值是int,则可以从第一个枚举迭代到最后一个枚举:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | enum Suit: Int { case Spades = 1 case Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return"spades" case .Hearts: return"hearts" case .Diamonds: return"diamonds" case .Clubs: return"clubs" } } } for i in Suit.Spades.toRaw()...Suit.Clubs.toRaw() { if let covertedSuit = Suit.fromRaw(i) { let description = covertedSuit.simpleDescription() } } |
其中一个问题是,在运行simpleDescription方法之前需要测试可选值,因此我们首先将convertedSuit设置为我们的值,然后将常量设置为convertedSuit.simpleDescription()。
这是我建议的方法。这并不完全令人满意(我对斯威夫特和OOP很陌生!)但也许有人能改进它。其思想是让每个枚举以.First和.Last属性的形式提供自己的范围信息。它只向每个枚举添加两行代码:仍然有点硬编码,但至少它没有复制整个集合。它确实需要将suit枚举修改为int,就像rank枚举一样,而不是非untyped。
这里是我添加到rank枚举中的代码,它位于case语句之后(suit枚举类似),而不是返回整个解决方案:
1 2 | var first: Int { return Ace.toRaw() } var last: Int { return King.toRaw() } |
我用来构建甲板作为字符串数组的循环。(问题定义没有说明甲板的结构。)
1 2 3 4 5 6 7 8 9 10 11 | func createDeck() -> [String] { var deck: [String] = [] var card: String for r in Rank.Ace.first...Rank.Ace.last { for s in Suit.Hearts.first...Suit.Hearts.last { card = Rank.simpleDescription( Rank.fromRaw(r)!)() +" of" + Suit.simpleDescription( Suit.fromRaw(s)!)() deck.append( card) } } return deck } |
这是不令人满意的,因为属性与元素而不是枚举相关联。但它确实为"for"循环增加了清晰度。我想说的是rank.first而不是rank.ace.first。它(对任何元素)都有效,但很难看。有人能演示如何将其提升到枚举级别吗?
为了让它工作,我把createDeck方法从card结构中提取出来…无法确定如何从该结构中获取返回的[string]数组,这似乎是放置此类方法的不好地方。
我使用了computed属性,它返回所有值的数组(感谢本文http://natecook.com/blog/2014/10/loopy random enum ideas/)。但是它也使用int raw值,但我不需要在单独的属性中重复枚举的所有成员。
更新xcode6.1有点改变了如何使用原始值获取枚举成员的方法,所以我修复了清单。还修复了第一个原始值错误的小错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | enum ValidSuits:Int{ case Clubs=0, Spades, Hearts, Diamonds func description()->String{ switch self{ case .Clubs: return"??" case .Spades: return"??" case .Diamonds: return"??" case .Hearts: return"??" } } static var allSuits:[ValidSuits]{ return Array( SequenceOf { () -> GeneratorOf<ValidSuits> in var i=0 return GeneratorOf<ValidSuits>{ return ValidSuits(rawValue: i++) } } ) } } |
另一个解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | enum Suit: String { case spades ="?" case hearts ="?" case diamonds ="?" case clubs ="?" static var count: Int { return 4 } init(index: Int) { switch index { case 0: self = .spades case 1: self = .hearts case 2: self = .diamonds default: self = .clubs } } } for i in 0..<Suit.count { print(Suit(index: i).rawValue) } |
在处理
我在
1 | enum Suit: Int { |
然后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | struct Card { var rank: Rank var suit: Suit func fullDeck()-> [Card] { var deck = [Card]() for i in Rank.Ace.rawValue...Rank.King.rawValue { for j in Suit.Spades.rawValue...Suit.Clubs.rawValue { deck.append(Card(rank:Rank(rawValue: i)! , suit: Suit(rawValue: j)!)) } } return deck } } |
这里,我使用一个方法来迭代一个枚举,并从一个枚举中提供多个值类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | enum IterateEnum: Int { case Zero case One case Two case Three case Four case Five case Six case Seven //tuple allows multiple values to be derived from the enum case, and //since it is using a switch with no default, if a new case is added, //a compiler error will be returned if it doesn't have a value tuple set var value: (french:String, spanish:String, japanese:String) { switch self { case .Zero: return (french:"zéro", spanish:"cero", japanese:"nuru") case .One: return (french:"un", spanish:"uno", japanese:"ichi") case .Two: return (french:"deux", spanish:"dos", japanese:"ni") case .Three: return (french:"trois", spanish:"tres", japanese:"san") case .Four: return (french:"quatre", spanish:"cuatro", japanese:"shi") case .Five: return (french:"cinq", spanish:"cinco", japanese:"go") case .Six: return (french:"six", spanish:"seis", japanese:"roku") case .Seven: return (french:"sept", spanish:"siete", japanese:"shichi") } } //Used to iterate enum or otherwise access enum case by index order. //Iterate by looping until it returns nil static func item(index:Int) -> IterateEnum? { return IterateEnum.init(rawValue: index) } static func numberFromSpanish(number:String) -> IterateEnum? { return findItem { $0.value.spanish == number } } //use block to test value property to retrieve the enum case static func findItem(predicate:((_:IterateEnum)->Bool)) -> IterateEnum? { var enumIndex:Int = -1 var enumCase:IterateEnum? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = IterateEnum.item(index: enumIndex) if let eCase = enumCase { if predicate(eCase) { return eCase } } } while enumCase != nil return nil } } var enumIndex:Int = -1 var enumCase:IterateEnum? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = IterateEnum.item(index: enumIndex) if let eCase = enumCase { print("The number \(eCase) in french: \(eCase.value.french), spanish: \(eCase.value.spanish), japanese: \(eCase.value.japanese)") } } while enumCase != nil print("Total of \(enumIndex) cases") let number = IterateEnum.numberFromSpanish(number:"siete") print("siete in japanese: \((number?.value.japanese ??"Unknown"))") |
这是输出:
法语中的数字零:z_ro,西班牙语:cero,日语:nuru法语第一:联合国,西班牙语:联合国,日语:一法语排名第二:双人舞,西班牙语:dos,日语:ni法语排名第三:特洛伊语,西班牙语:tres,日语:san法语第四名:quatre,西班牙语:cuatro,日语:shi法语第五名:cinq,西班牙语:cinco,日语:go法语六号:六,西班牙语:塞浦路斯,日语:韩国法语排名第七:九月,西班牙语:锡特,日语:志
共8例
日文Siete:Shichi
更新
我最近创建了一个处理枚举的协议。协议需要一个具有int原始值的枚举:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | protocol EnumIteration { //Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil static func item(index:Int) -> Self? static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) { static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? static func count() -> Int } extension EnumIteration where Self: RawRepresentable, Self.RawValue == Int { //Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil static func item(index:Int) -> Self? { return Self.init(rawValue: index) } static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) if let eCase = enumCase { item(index: enumIndex, enumCase: eCase) } } while enumCase != nil completion?() } static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) if let eCase = enumCase { if predicate(enumCase:eCase) { return eCase } } } while enumCase != nil return nil } static func count() -> Int { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) } while enumCase != nil //last enumIndex (when enumCase == nil) is equal to the enum count return enumIndex } } |
这是一个相当古老的帖子,来自Swift2.0。现在有一些更好的解决方案使用了Swift 3.0的新功能:在swift 3.0中迭代枚举
在这个问题上,有一个解决方案使用了Swift4.2的一个新特性(在我写这个编辑的时候还没有发布):如何获得swift枚举的计数?
这个线程和其他线程中有很多好的解决方案,但是其中一些非常复杂。我喜欢尽可能简化。这里有一个解决方案,可能适用于不同的需求,也可能不适用于不同的需求,但我认为它在大多数情况下都能很好地工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | enum Number: String { case One case Two case Three case Four case EndIndex func nextCase () -> Number { switch self { case .One: return .Two case .Two: return .Three case .Three: return .Four case .Four: return .EndIndex /* Add all additional cases above */ case .EndIndex: return .EndIndex } } static var allValues: [String] { var array: [String] = Array() var number = Number.One while number != Number.EndIndex { array.append(number.rawValue) number = number.nextCase() } return array } } |
迭代:
1 2 3 | for item in Number.allValues { print("number is: \(item)") } |
正如这里的@kametrixom answer一样,我相信返回数组比返回任何序列都要好,因为您可以访问数组的所有优点,如count等。
这是重写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public protocol EnumCollection : Hashable {} extension EnumCollection { public static func allValues() -> [Self] { typealias S = Self let retVal = AnySequence { () -> AnyGenerator<S> in var raw = 0 return AnyGenerator { let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory } guard current.hashValue == raw else { return nil } raw += 1 return current } } return [S](retVal) } } |
(Karthik Kumar答案的改进)
这个解决方案使用编译器来保证您不会错过任何案例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | enum Suit: String { case spades ="?" case hearts ="?" case diamonds ="?" case clubs ="?" static var enumerate: [Suit] { switch Suit.spades { // make sure the two lines are identical ^_^ case .spades, .hearts, .diamonds, .clubs: return [.spades, .hearts, .diamonds, .clubs] } } } |
我使用了下面的方法,假设我知道排名枚举中的最后一个值,并且所有排名在ace之后都有增量值。
我喜欢这样,因为它又干净又小,容易理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | func cardDeck() -> Card[] { var cards: Card[] = [] let minRank = Rank.Ace.toRaw() let maxRank = Rank.King.toRaw() for rank in minRank...maxRank { if var convertedRank: Rank = Rank.fromRaw(rank) { cards.append(Card(rank: convertedRank, suite: Suite.Clubs)) cards.append(Card(rank: convertedRank, suite: Suite.Diamonds)) cards.append(Card(rank: convertedRank, suite: Suite.Hearts)) cards.append(Card(rank: convertedRank, suite: Suite.Spades)) } } return cards } |
有一个聪明的方法,令人沮丧,因为它说明了两种不同的枚举之间的区别。
试试这个:
1 2 3 4 5 6 7 8 9 10 | func makeDeck() -> Card[] { var deck: Card[] = [] var suits: Suit[] = [.Hearts, .Diamonds, .Clubs, .Spades] for i in 1...13 { for suit in suits { deck += Card(rank: Rank.fromRaw(i)!, suit: suit) } } return deck } |
协议是,由数字(原始值)支持的枚举是隐式显式排序的,而不由数字支持的枚举是隐式无序的。
例如,当我们给出枚举值数字时,语言就足够巧妙地计算出数字的顺序。另一方面,如果我们不给它任何排序,当我们试图迭代这些值时,语言就会把它的手举到空中,然后说"是的,但是你想先去哪一个?"??"
可以这样做的其他语言(迭代无序的枚举)可能是相同的语言,其中所有东西都是"在引擎盖下"的,实际上是一个映射或字典,并且您可以迭代映射的键,不管是否有任何逻辑顺序。
所以诀窍是为它提供一些显式排序的东西,在本例中是按照我们想要的顺序排列数组中的西服实例。一旦你这么做了,斯威夫特就会说:"那你为什么不先这么说呢?"
另一个速记技巧是在fromraw函数上使用forcing操作符。这说明了另一个关于枚举的"gotcha",即传递的可能值的范围通常大于枚举的范围。例如,如果我们说rank.fromraw(60),就不会返回值,所以我们使用语言的可选功能,在这里我们开始使用选项,随后将强制执行。(或者,如果让我来建造,我觉得还是有点奇怪)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | enum Rank: Int { case Ace = 0 case Two, Three, Four, Five, Six, Seve, Eight, Nine, Ten case Jack, Queen, King case Count } enum Suit : Int { case Spades = 0 case Hearts, Diamonds, Clubs case Count } struct Card { var rank:Rank var suit:Suit } class Test { func makeDeck() -> Card[] { let suitsCount:Int = Suit.Count.toRaw() let rankCount:Int = Rank.Count.toRaw() let repeatedCard:Card = Card(rank:Rank.Ace, suit:Suit.Spades) let deck:Card[] = Card[](count:suitsCount*rankCount, repeatedValue:repeatedCard) for i:Int in 0..rankCount { for j:Int in 0..suitsCount { deck[i*suitsCount+j] = Card(rank: Rank.fromRaw(i)!, suit: Suit.fromRaw(j)!) } } return deck } } |
根据瑞克的回答:这比以前快了5倍
它花费了我更多的时间,然后只是结构中的一个方法,比如swift book调用的方法,但是我在枚举中设置了下一个函数。我本可以使用一个协议的,我不知道为什么,但把等级设置为int会搞砸它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self{ case .Ace: return"ace" case .Jack: return"jack" case .Queen: return"Queen" case .King: return"King" default: return String(self.toRaw()) } } mutating func next() -> Rank { var rank = self var rawrank = rank.toRaw() var nrank:Rank = self rawrank = rawrank + 1 if let newRank = Rank.fromRaw(rawrank) { println("\(newRank.simpleDescription())") nrank = newRank } else { return self } return nrank } } enum Suit { case Spades, Hearts, Diamonds, Clubs func color() -> String { switch self{ case .Spades, .Clubs: return"black" default: return"red" } } func simpleDescription() -> String { switch self{ case .Spades: return"spades" case .Hearts: return"hearts" case .Diamonds: return"diamonds" case .Clubs: return"clubs" } } mutating func next() -> Suit { switch self{ case .Spades: return Hearts case .Hearts: return Diamonds case .Diamonds: return Clubs case .Clubs: return Spades } } } struct Card { var rank:Rank var suit:Suit func deck() -> Card[] { var tRank = self.rank var tSuit = self.suit let tcards = 52 // we start from 0 var cards: Card[] = [] for i in 0..tcards{ var card = Card(rank: tRank, suit: tSuit) cards.append(card) tRank = tRank.next() tSuit = tSuit.next() } return cards } func simpleDescription() -> String { return"The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } var card = Card(rank: .Ace, suit: .Spades) var deck = card.deck() |
希望这基本上有助于我使用一些一般知识,但可以通过将套装乘以等级(如果你不使用标准卡片组,你必须相应地更改枚举,如果基本上只是通过不同的枚举来节省时间,我使用等级原始值,如果你想要的,但是这个例子没有,所以我决定在不改变原值的情况下解决它。
我发现了一种有点刺耳的感觉,但这样做更安全,不需要输入两次值或引用枚举值的内存,使得它不太可能被破坏。
基本上,不要使用枚举,而是使用一个实例创建一个结构,并将所有枚举值设置为常量。然后可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public struct Suit{ // the values let spades ="?" let hearts ="?" let diamonds ="?" let clubs ="?" // make a single instance of the Suit struct, Suit.instance struct SStruct{static var instance: Suit = Suit()} static var instance : Suit{ get{return SStruct.instance} set{SStruct.instance = newValue} } // an array with all of the raw values static var allValues: [String]{ var values = [String]() let mirror = Mirror(reflecting: Suit.instance) for (_, v) in mirror.children{ guard let suit = v as? String else{continue} values.append(suit) } return values } } |
如果使用此方法,要获得单个值,需要使用
但所有这些都很无聊…让我们做一些事情,让它更像一个真正的枚举!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | public struct SuitType{ // store multiple things for each suit let spades = Suit("?", order: 4) let hearts = Suit("?", order: 3) let diamonds = Suit("?", order: 2) let clubs = Suit("?", order: 1) struct SStruct{static var instance: SuitType = SuitType()} static var instance : SuitType{ get{return SStruct.instance} set{SStruct.instance = newValue} } // a dictionary mapping the raw values to the values static var allValuesDictionary: [String : Suit]{ var values = [String : Suit]() let mirror = Mirror(reflecting: SuitType.instance) for (_, v) in mirror.children{ guard let suit = v as? Suit else{continue} values[suit.rawValue] = suit } return values } } public struct Suit: RawRepresentable, Hashable{ public var rawValue: String public typealias RawValue = String public var hashValue: Int{ // find some integer that can be used to uniquely identify // each value. In this case, we could have used the order // variable because it is a unique value, yet to make this // apply to more cases, the hash table address of rawValue // will be returned, which should work in almost all cases // // you could also add a hashValue parameter to init() and // give each suit a different hash value return rawValue.hash } public var order: Int public init(_ value: String, order: Int){ self.rawValue = value self.order = order } // an array of all of the Suit values static var allValues: [Suit]{ var values = [Suit]() let mirror = Mirror(reflecting: SuitType.instance) for (_, v) in mirror.children{ guard let suit = v as? Suit else{continue} values.append(suit) } return values } // allows for using Suit(rawValue:"?"), like a normal enum public init?(rawValue: String){ // get the Suit from allValuesDictionary in SuitType, or return nil if that raw value doesn't exist guard let suit = SuitType.allValuesDictionary[rawValue] else{return nil} // initialize a new Suit with the same properties as that with the same raw value self.init(suit.rawValue, order: suit.order) } } |
你现在可以做像
1 | let allSuits: [Suit] = Suit.allValues |
或
1 2 3 | for suit in Suit.allValues{ print("The suit \(suit.rawValue) has the order \(suit.order)") } |
但是,要买单程票,你还是需要使用
1 2 3 4 5 6 7 | public struct Suit: RawRepresentable, Hashable{ // ...your code... static var type = SuitType.instance // ...more of your code... } |
你现在可以用
Swift 5解决方案:Swift 5中的解决方案非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 | enum Suit: String, CaseIterable { case spades ="?" case hearts ="?" case diamonds ="?" case clubs ="?" } // then access the cases like this: for suitKey in LocalizationKey.allCases { print(suitKey) } |
有时,您可以使用在整个软件开发生命周期中更改的底层原始整数类型来处理枚举类型。下面是一个很好的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class MyClassThatLoadsTexturesEtc { //... // Colors used for gems and sectors. public enum Color: Int { // Colors arranged in order of the spectrum. case First = 0 case Red, Orange, Yellow, Green, Blue, Purple, Pink // --> Add more colors here, between the first and last markers. case Last } //... public func preloadGems() { // Preload all gems. for i in (Color.First.toRaw() + 1) ..< (Color.Last.toRaw()) { let color = Color.fromRaw(i)! loadColoredTextures(forKey: color) } } //... } |
我的解决方案是声明一个具有所有枚举可能性的数组,以便for可以遍历所有枚举可能性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //Function inside struct Card static func generateFullDeck() -> [Card] { let allRanks = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King] let allSuits = [Suit.Hearts, Suit.Diamonds, Suit.Clubs, Suit.Spades] var myFullDeck: [Card] = [] for myRank in allRanks { for mySuit in allSuits { myFullDeck.append(Card(rank: myRank, suit: mySuit)) } } return myFullDeck } //actual use: let aFullDeck = Card.generateFullDeck() //Generate the desired full deck var allDesc: [String] = [] for aCard in aFullDeck { println(aCard.simpleDescription()) //You'll see all the results in playground } |
我添加了函数count(),并迭代这些值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public enum MetricType : Int { case mvps = 0 case allNBA = 1 case championshipRings = 2 case finalAppearances = 3 case gamesPlayed = 4 case ppg = 5 static func count() -> Int { return (ppg.rawValue) + 1 } static var allValues: [MetricType] { var array: [MetricType] = Array() var item : MetricType = MetricType.mvps while item.rawValue < MetricType.count() { array.append(item) item = MetricType(rawValue: (item.rawValue + 1))! } return array } |
}
在swift上,可以访问
大多数情况下,只有当您有一些选择要处理,并且确切知道要对每种类型做什么时,才使用
在使用
您可以这样做,例如:
1 2 3 4 5 6 7 8 9 | func sumNumbers(numbers : Int...) -> Int { var sum = 0 for number in numbers{ sum += number } return sum } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return"ace" case .Jack: return"jack" case .Queen: return"queen" case .King: return"king" default: return String(self.toRaw()) } } } enum Suit: Int { case Spades = 1 case Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return"spades" case .Hearts: return"hearts" case .Diamonds: return"diamonds" case .Clubs: return"clubs" } } func color() -> String { switch self { case .Spades, .Clubs: return"black" case .Hearts, .Diamonds: return"red" } } } struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return"The \(rank.simpleDescription()) of \(suit.simpleDescription())" } static func createPokers() -> Card[] { let ranks = Array(Rank.Ace.toRaw()...Rank.King.toRaw()) let suits = Array(Suit.Spades.toRaw()...Suit.Clubs.toRaw()) let cards = suits.reduce(Card[]()) { (tempCards, suit) in tempCards + ranks.map { rank in Card(rank: Rank.fromRaw(rank)!, suit: Suit.fromRaw(suit)!) } } return cards } } |
这里有一个不那么神秘的例子,如果您仍然想对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | enum Rank: Int { case Ace = 1, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King func name() -> String { switch self { case .Ace: return"ace" case .Jack: return"jack" case .Queen: return"queen" case .King: return"king" default: return String(self.toRaw()) } } } enum Suit: Int { case Diamonds = 1, Clubs, Hearts, Spades func name() -> String { switch self { case .Diamonds: return"diamonds" case .Clubs: return"clubs" case .Hearts: return"hearts" case .Spades: return"spades" default: return"NOT A VALID SUIT" } } } let Ranks = [ Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King ] let Suits = [ Suit.Diamonds, Suit.Clubs, Suit.Hearts, Suit.Spades ] class Card { var rank: Rank var suit: Suit init(rank: Rank, suit: Suit) { self.rank = rank self.suit = suit } } class Deck { var cards = Card[]() init() { for rank in Ranks { for suit in Suits { cards.append(Card(rank: rank, suit: suit)) } } } } var myDeck = Deck() myDeck.cards.count // => 52 |