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)
}

其他回答

在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)")
}

它花了我一点,而不仅仅是一个方法在结构像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的情况下找出它

以下是我的建议。这不是完全令人满意的(我对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]数组,这似乎是一个糟糕的地方,把这样的方法无论如何。

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
    }
}

这个怎么样?

另一个解决方案:

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)
}