enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
例如,我怎么做这样的事情:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
结果示例:
♠
♥
♦
♣
enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
例如,我怎么做这样的事情:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
结果示例:
♠
♥
♦
♣
当前回答
编辑: 快速进化提案SE-0194枚举案例派生集合为这个问题提出了一个水平的解决方案。我们在Swift 4.2和更新版本中看到了它。该提案还指出了一些变通方法,这些方法与这里已经提到的一些方法类似,但可能会很有趣。
为了完整起见,我也会保留我原来的职位。
这是基于@Peymmankh的回答的另一种方法,适用于Swift 3。
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)
}
其他回答
有一种聪明的方法,尽管令人沮丧,但它说明了两种不同类型的枚举之间的区别。
试试这个:
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
}
交易是,一个由数字(原始值)支持的枚举是隐式显式有序的,而一个没有数字支持的枚举是显式隐式无序的。
例如,当我们给枚举值数字时,语言足够狡猾,可以找出数字的顺序。 另一方面,如果我们不给它任何顺序,当我们尝试迭代这些值时,语言就会举起双手说:“是的,但你想先执行哪个??”
其他可以做到这一点(迭代无序枚举)的语言可能是相同的语言,其中所有内容实际上都是一个地图或字典,你可以迭代地图的键,无论是否有任何逻辑顺序。
诀窍是给它提供一些显式排序的东西,在这个例子中,suit的实例在数组中按照我们想要的顺序。一旦你这么说,霉霉就会说“你为什么不一开始就这么说呢?”
另一个简写技巧是在fromRaw函数上使用强制操作符。这说明了关于枚举的另一个“陷阱”,即可能传入的值的范围通常大于枚举的范围。例如,如果我们说Rank.fromRaw(60),就不会返回值,所以我们使用了语言的可选特性,在我们开始使用可选特性的地方,很快就会出现强制。(或者交替if let结构,这对我来说仍然有点奇怪)
这是一个相当老的帖子,来自Swift 2.0。现在有一些更好的解决方案,使用了swift 3.0的新特性: 在Swift 3.0中迭代一个Enum
关于这个问题,有一个解决方案,它使用了Swift 4.2的一个新功能(在我写这篇编辑时还没有发布): 我如何得到一个Swift枚举的计数?
在这个帖子中有很多好的解决方案,但其中一些非常复杂。我喜欢尽可能地简化。这里有一个解决方案,可能适用于不同的需求,但我认为它在大多数情况下都很好:
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
}
}
迭代:
for item in Number.allValues {
print("number is: \(item)")
}
其他的解决方法都是可行的,但它们都假设了可能的等级和花色的数量,或者第一和最后的等级是什么。的确,在可预见的未来,一副纸牌的布局可能不会有太大变化。然而,一般来说,编写尽可能少假设的代码会更简洁。我的解决方案:
我已经在Suit枚举中添加了一个原始类型,所以我可以使用Suit(rawValue:)来访问Suit案例:
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语句中展开并检查它的值,不需要假设Rank或Suit情况的数量:
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方法:
let card = Card(rank: Rank.Ace, suit: Suit.Clubs)
let deck = card.createDeck()
您可以通过实现ForwardIndexType协议来迭代枚举。
ForwardIndexType协议要求您定义一个继任者()函数来逐级遍历元素。
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)!
}
在开或闭范围内迭代(..<或…)将在内部调用继任者()函数,允许你这样写:
// 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
}
我的解决方案是声明一个包含所有枚举可能性的数组。所以for循环可以遍历所有这些。
//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
}