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)
}
结果示例:
♠
♥
♦
♣
当前回答
在Swift 3中,当底层枚举有rawValue时,你可以实现Strideable协议。优点是不像其他建议那样创建值数组,并且标准的Swift“for in”循环工作,这是一个很好的语法。
// "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)")
}
其他回答
这看起来像一个黑客,但如果你使用原始值,你可以这样做
enum Suit: Int {
case Spades = 0, Hearts, Diamonds, Clubs
...
}
var suitIndex = 0
while var suit = Suit.fromRaw(suitIndex++) {
...
}
如果你给枚举一个原始的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
}
}
Swift 5解决方案:
enum Suit: String, CaseIterable {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
// access cases like this:
for suitKey in Suit.allCases {
print(suitKey)
}
对不起,我的回答是具体到我如何在我需要做的事情中使用这篇文章。对于那些无意中遇到这个问题的人,寻找一种方法在枚举中找到一个case,这是一种方法(Swift 2新增):
编辑:小写驼峰现在是Swift 3 enum值的标准
// 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示例代码包含了完全相同的技术。
也就是说,他们应该在语言中构建一个更方便的机制(苹果,你在听吗?)
原则上,如果你不为enum的大小写使用原始值赋值,这样做是可能的:
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())")
}