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)
}
结果示例:
♠
♥
♦
♣
当前回答
如果你给枚举一个原始的Int值,它将使循环更容易。
例如,你可以使用anyGenerator来获得一个可以枚举你的值的生成器:
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())
然而,这看起来像一个相当常见的模式,如果我们可以通过简单地遵循协议使任何枚举类型可枚举,这不是很好吗?有了Swift 2.0和协议扩展,现在我们可以了!
简单地添加到你的项目:
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原始值),你可以通过遵循协议使它可枚举:
enum Rank: Int, EnumerableEnum {
case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}
// ...
for rank in Rank.enumerate() { ... }
如果你的枚举值不以0开头(默认值),重写firstRawValue方法:
enum DeckColor: Int, EnumerableEnum {
case Red = 10, Blue, Black
static func firstRawValue() -> Int { return Red.rawValue }
}
// ...
let colors = Array(DeckColor.enumerate())
最后一个Suit类,包括用更标准的CustomStringConvertible协议替换simpleDescription,看起来像这样:
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)
}
Swift 3语法:
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
}
}
其他回答
我使用计算属性,它返回所有值的数组(感谢这篇文章http://natecook.com/blog/2014/10/loopy-random-enum-ideas/)。但是,它也使用int原始值,但我不需要在单独的属性中重复枚举的所有成员。
Xcode 6.1在如何使用rawValue获取enum成员方面做了一点改变,所以我修正了listing。还修复了第一个rawValue错误的小错误。
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++)
}
}
)
}
}
以下是我的建议。这不是完全令人满意的(我对Swift和OOP很陌生!),但也许有人可以改进它。这个想法是让每个枚举提供自己的范围信息作为.first和.last属性。它只向每个枚举添加了两行代码:仍然有点硬编码,但至少它没有复制整个集合。它确实需要将Suit enum修改为Int类型,就像Rank enum一样,而不是无类型的。
而不是重复整个解决方案,下面是我添加到。在case语句之后的某个地方(Suit enum类似):
var first: Int { return Ace.toRaw() }
var last: Int { return King.toRaw() }
以及我用来将deck构建为String数组的循环。(问题定义没有说明牌组是如何构造的。)
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
}
这并不令人满意,因为属性与元素而不是enum相关联。但它确实为“for”循环增加了清晰度。我希望它是Rank。而不是Rank.Ace.first。它适用于任何元素,但很难看。有人能演示一下如何将其提升到enum级别吗?
为了使它工作,我从Card结构中提取了createDeck方法。我不知道如何从该结构返回一个[String]数组,这似乎是一个糟糕的地方,把这样的方法无论如何。
它花了我一点,而不仅仅是一个方法在结构像swift书调用,但我在枚举中设置了下一个函数。我会使用一个协议,我不知道为什么,但有秩设置为int混乱。
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()
我使用了一些常识,但这可以通过将花色乘以等级来轻松纠正(如果你没有使用标准的桥牌,你必须相应地改变枚举,如果基本上只是通过不同的枚举进行步骤)。为了节省时间,我使用了ranks rawValues,如果你愿意,你也可以为西装做同样的事情。然而,这个例子没有它,所以我决定在不改变suit rawValue的情况下找出它
您可以通过实现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
}
该解决方案在可读性和可维护性之间取得了适当的平衡。
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()