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结构,这对我来说仍然有点奇怪)
枚举有toRaw()和fromRaw()方法。所以如果你的原始值是Int,你可以从第一个枚举迭代到最后一个枚举:
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()
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
}
}
该解决方案在可读性和可维护性之间取得了适当的平衡。
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()
你可以试着像这样列举
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]