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)
}
결과 예 :
♠
♥
♦
♣
답변:
시작 스위프트 4.2 (엑스 코드 10), 단지에 프로토콜 적합성을 추가 CaseIterable
혜택을 allCases
. 이 프로토콜 적합성을 추가하려면 다음과 같이 작성하면됩니다.
extension Suit: CaseIterable {}
열거 형이 자신의 것이라면 선언에 직접 적합성을 지정할 수 있습니다.
enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }
그런 다음 다음 코드는 가능한 모든 값을 인쇄합니다.
Suit.allCases.forEach {
print($0.rawValue)
}
Swift 3.x 또는 4.0을 지원해야하는 경우 다음 코드를 추가하여 Swift 4.2 구현을 모방 할 수 있습니다.
#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif
String
현재 스택 오버플로 질문과 달리 열거 형이 백업되지 않은 간단한 예제를 사용했습니다 .
이 게시물은 여기 관련이 있습니다 https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift
본질적으로 제안 된 솔루션은
enum ProductCategory : String {
case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
static let allValues = [Washers, Dryers, Toasters]
}
for category in ProductCategory.allValues{
//Do something
}
Enum.Values(typeof(FooEnum))
맵 또는 축소와 같은 확장 방법으로 노출 할 수는 있지만 C # 구현과 비슷한 것이 있습니다 . FooEnum.values() :: values(EnumType -> [EnumType])
iterateEnum()
임의 enum
유형의 경우를 반복 하는 유틸리티 기능 을 만들었습니다 .
사용법 예는 다음과 같습니다.
enum Suit: String {
case Spades = "♠"
case Hearts = "♥"
case Diamonds = "♦"
case Clubs = "♣"
}
for f in iterateEnum(Suit) {
println(f.rawValue)
}
어떤 출력 :
♠
♥
♦
♣
그러나 이것은 디버그 또는 테스트 목적으로 만 사용됩니다. 이것은 문서화되지 않은 여러 Swift1.1 컴파일러 동작에 의존하므로 사용자가 위험을 감수해야합니다.
코드는 다음과 같습니다.
func iterateEnum<T: Hashable>(_: T.Type) -> GeneratorOf<T> {
var cast: (Int -> T)!
switch sizeof(T) {
case 0: return GeneratorOf(GeneratorOfOne(unsafeBitCast((), T.self)))
case 1: cast = { unsafeBitCast(UInt8(truncatingBitPattern: $0), T.self) }
case 2: cast = { unsafeBitCast(UInt16(truncatingBitPattern: $0), T.self) }
case 4: cast = { unsafeBitCast(UInt32(truncatingBitPattern: $0), T.self) }
case 8: cast = { unsafeBitCast(UInt64($0), T.self) }
default: fatalError("cannot be here")
}
var i = 0
return GeneratorOf {
let next = cast(i)
return next.hashValue == i++ ? next : nil
}
}
기본 아이디어는 다음과 같습니다.
enum
제외하고, enum
관련 유형들, 사건의 개수가 일 때의 경우 단지 인덱스 2...256
, 그것은 동일의 UInt8
경우, 257...65536
그것의, UInt16
등등. 따라서 unsafeBitcast
해당 부호없는 정수 유형이 될 수 있습니다 ..hashValue
enum 값은 케이스의 인덱스와 동일합니다..hashValue
유효하지 않은 인덱스 에서 비트 캐스트 된 열거 형 값 은 0
입니다.Swift2 용으로 수정 되었고 @Kametrixom의 답변 에서 캐스팅 아이디어를 구현했습니다 .
func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
var i = 0
return anyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
return next.hashValue == i++ ? next : nil
}
}
Swift3 용으로 수정 :
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(to: &i) {
$0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee }
}
if next.hashValue != i { return nil }
i += 1
return next
}
}
Swift3.0.1 용으로 수정 :
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafeBytes(of: &i) { $0.load(as: T.self) }
if next.hashValue != i { return nil }
i += 1
return next
}
}
withUnsafePointer
withMemoryRebound
하고 pointee
, 물건을 모든 수단으로 사용합니다. 그렇지 않으면 피할 것입니다.
다른 솔루션은 작동 하지만 모두 가능한 순위 및 수 또는 첫 번째 및 마지막 순위가 무엇인지를 가정합니다. 사실, 카드 데크의 레이아웃은 아마도 가까운 미래에 크게 변하지 않을 것입니다. 그러나 일반적으로 가능한 적은 가정을하는 코드를 작성하는 것이 더 좋습니다. 내 해결책 :
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)
}
}
}
카드 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()
Suit
. 이 예에서는 가능하지만 운동은 enums
마치 마치 외부에서 온 것처럼 자신 과 함께 일할 수 있도록하기위한 것입니다 .
나는 비트와 바이트를 우연히 발견하고 나중에 @rintaro 의 답변 과 매우 유사한 작동을 발견 한 확장을 만들었습니다 . 다음과 같이 사용됩니다.
enum E : EnumCollection {
case A, B, C
}
Array(E.cases()) // [A, B, C]
주목할만한 것은 연관된 값이없는 모든 열거 형에서 사용할 수 있다는 것입니다. 케이스가없는 열거 형에는 작동하지 않습니다.
@rintaro 의 답변 과 마찬가지로이 코드는 열거 형의 기본 표현을 사용합니다. 이 표현은 문서화되지 않았으며 나중에 변경 될 수 있으며 이로 인해 문제가 발생할 수 있습니다. 프로덕션에서 이것을 사용하지 않는 것이 좋습니다.
코드 (Swift 2.2, Xcode 7.3.1, Xcode 10에서는 작동하지 않음) :
protocol EnumCollection : Hashable {}
extension EnumCollection {
static func cases() -> AnySequence<Self> {
typealias S = Self
return AnySequence { () -> AnyGenerator<S> in
var raw = 0
return AnyGenerator {
let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
}
}
코드 (Swift 3, Xcode 8.1, Xcode 10에서 작동하지 않음) :
protocol EnumCollection : Hashable {}
extension EnumCollection {
static func cases() -> AnySequence<Self> {
typealias S = Self
return AnySequence { () -> AnyIterator<S> in
var raw = 0
return AnyIterator {
let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
}
}
왜 필요한지 typealias
모르겠지만 컴파일러는 컴파일러없이 불평합니다.
withUnsafePointer
... pointee}
에 의해withUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
ForwardIndexType
프로토콜 을 구현하여 열거 형을 반복 할 수 있습니다 .
ForwardIndexType
프로토콜은 정의 할 필요 successor()
요소를 단계별로 기능을.
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)!
}
개방 또는 폐쇄 범위 ( ..<
또는 ...
)를 반복 하면 내부적으로 successor()
함수를 호출하여 다음과 같이 작성할 수 있습니다.
// 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
}
successor()
방법 (첫 번째 옵션) enum
을 사용하면 연관된 유형을 가질 필요가 없습니다 . +1
이 문제는 훨씬 쉬워졌습니다. 다음은 Swift 4.2 솔루션입니다.
enum Suit: Int, CaseIterable {
case None
case Spade, Heart, Diamond, Club
static let allNonNullCases = Suit.allCases[Spade.rawValue...]
}
enum Rank: Int, CaseIterable {
case Joker
case Two, Three, Four, Five, Six, Seven, Eight
case Nine, Ten, Jack, Queen, King, Ace
static let allNonNullCases = Rank.allCases[Two.rawValue...]
}
func makeDeck(withJoker: Bool = false) -> [Card] {
var deck = [Card]()
for suit in Suit.allNonNullCases {
for rank in Rank.allNonNullCases {
deck.append(Card(suit: suit, rank: rank))
}
}
if withJoker {
deck.append(Card(suit: .None, rank: .Joker))
}
return deck
}
4.2 이전
나는 " Swift의 List comprehension "을 찾은 후이 솔루션을 좋아한다 .
문자열 대신 Int raws를 사용하지만 두 번 입력하지 않고 범위를 사용자 정의 할 수 있으며 원시 값을 하드 코딩하지 않습니다.
이것은 내 원래 솔루션의 Swift 4 버전이지만 위의 4.2 개선 사항을 참조하십시오.
enum Suit: Int {
case None
case Spade, Heart, Diamond, Club
static let allRawValues = Suit.Spade.rawValue...Suit.Club.rawValue
static let allCases = Array(allRawValues.map{ Suit(rawValue: $0)! })
}
enum Rank: Int {
case Joker
case Two, Three, Four, Five, Six
case Seven, Eight, Nine, Ten
case Jack, Queen, King, Ace
static let allRawValues = Rank.Two.rawValue...Rank.Ace.rawValue
static let allCases = Array(allRawValues.map{ Rank(rawValue: $0)! })
}
func makeDeck(withJoker: Bool = false) -> [Card] {
var deck = [Card]()
for suit in Suit.allCases {
for rank in Rank.allCases {
deck.append(Card(suit: suit, rank: rank))
}
}
if withJoker {
deck.append(Card(suit: .None, rank: .Joker))
}
return deck
}
원칙적으로 열거 형의 경우 원시 값 할당을 사용하지 않는다고 가정하면이 방법으로 수행 할 수 있습니다.
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())")
}
enum ItWontWorkForThisEnum {case a, b, c}
열거 형 에 원시 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 raw 값이있는 한) 프로토콜을 준수하여 열거 형을 만들 수 있습니다.
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())
표준 CustomStringConvertible 프로토콜로 교체 simpleDescription
하는 것을 포함하여 최종 Suit 클래스 는 다음과 같습니다.
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)
}
스위프트 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
}
}
로 업데이트 스위프트 2.2 +
func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) {
UnsafePointer<T>($0).memory
}
if next.hashValue == i {
i += 1
return next
} else {
return nil
}
}
}
@Kametrixom의 답변 으로 Swift 2.2 형식으로 코드가 업데이트되었습니다.
대한 스위프트 3.0 이상 (많은 감사 @Philip )
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(&i) {
UnsafePointer<T>($0).pointee
}
if next.hashValue == i {
i += 1
return next
} else {
return nil
}
}
}
.allValues
내 코드 전체 에서 많은 일을했습니다 . 나는 마침내 Iteratable
프로토콜을 따르고 방법을 갖는 방법을 알아 냈습니다 rawValues()
.
protocol Iteratable {}
extension RawRepresentable where Self: RawRepresentable {
static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(to: &i) {
$0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee }
}
if next.hashValue != i { return nil }
i += 1
return next
}
}
}
extension Iteratable where Self: RawRepresentable, Self: Hashable {
static func hashValues() -> AnyIterator<Self> {
return iterateEnum(self)
}
static func rawValues() -> [Self.RawValue] {
return hashValues().map({$0.rawValue})
}
}
// Example
enum Grocery: String, Iteratable {
case Kroger = "kroger"
case HEB = "h.e.b."
case Randalls = "randalls"
}
let groceryHashes = Grocery.hashValues() // AnyIterator<Grocery>
let groceryRawValues = Grocery.rawValues() // ["kroger", "h.e.b.", "randalls"]
enum Filter: String, CaseIterable {
case salary = "Salary"
case experience = "Experience"
case technology = "Technology"
case unutilized = "Unutilized"
case unutilizedHV = "Unutilized High Value"
static let allValues = Filter.allCases.map { $0.rawValue }
}
불러라
print(Filter.allValues)
인쇄물:
[ "급여", "경험", "기술", "사용되지 않음", "사용되지 않은 높은 가치"]
enum
표현Int
enum Filter: Int {
case salary
case experience
case technology
case unutilized
case unutilizedHV
static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case
static let allValues = allRawValues.map { Filter(rawValue: $0)!.rawValue }
}
다음과 같이 호출하십시오.
print(Filter.allValues)
인쇄물:
[0, 1, 2, 3, 4]
enum
표현String
enum Filter: Int {
case salary
case experience
case technology
case unutilized
case unutilizedHV
static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case
static let allValues = allRawValues.map { Filter(rawValue: $0)!.description }
}
extension Filter: CustomStringConvertible {
var description: String {
switch self {
case .salary: return "Salary"
case .experience: return "Experience"
case .technology: return "Technology"
case .unutilized: return "Unutilized"
case .unutilizedHV: return "Unutilized High Value"
}
}
}
불러라
print(Filter.allValues)
인쇄물:
[ "급여", "경험", "기술", "사용되지 않음", "사용되지 않은 높은 가치"]
편집 : Swift Evolution 제안 SE-0194 Enum Cases 파생 컬렉션은 이 문제에 대한 수준의 해결책 을 제안합니다 . 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)
}
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 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]
static var enumerate = [Mercury, Venus, Earth, Mars]
대부분의 투표 응답과 비교하여 하위 응답으로 만듭니다. stackoverflow.com/a/24137319/1033581
return [Mercury, Venus, Mars]
대신 쓰면 컴파일러가 불평하지 않습니다return [Mercury, Venus, Earth, Mars]
return [.spades, .hearts, .clubs]
로 바꾸면 컴파일러가 아무 말도하지 않고 코드에서 사용하려고 할 때 [TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]
-내 요점-큰 것을 다루는 경우 열거 형을 사용하면 때때로 사례를 추가하거나 제거해야하므로 솔루션이 누락 오류가 발생하기 쉬운 반면 현재 답변은 간결하지는 않지만 안전합니다.
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)")
}
이 솔루션은 가독성과 유지 관리 성의 적절한 균형을 유지합니다.
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()
죄송합니다. 제 답변은 내가해야 할 일에서이 게시물을 어떻게 사용했는지에 대한 것입니다. 이 질문을 우연히 발견 하고 열거 형 내에서 사례 를 찾는 방법을 찾고있는 사람들에게는이 방법이 있습니다 (Swift 2의 새로운 기능).
편집 : 소문자 camelCase는 이제 Swift 3 열거 형 값의 표준입니다.
// 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 용 최신 Apple 예제 코드에는 이와 동일한 기술이 포함되어 있습니다.
즉, 그들은 언어에보다 편리한 메커니즘을 구축해야합니다 (Apple, 듣고 있습니까?)!
실험은 : EXPERIMENT
등급과 수트의 각 조합으로 한 장의 카드로 한 벌의 카드를 만드는 방법을 카드에 추가하십시오.
따라서 메소드를 추가하는 것 이외의 주어진 코드를 수정하거나 향상시키지 않고 (그리고 아직 가르쳐지지 않은 것들을 사용하지 않고), 나는이 솔루션을 생각해 냈습니다.
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
func createDeck() -> [Card] {
var deck: [Card] = []
for rank in Rank.Ace.rawValue...Rank.King.rawValue {
for suit in Suit.Spades.rawValue...Suit.Clubs.rawValue {
let card = Card(rank: Rank(rawValue: rank)!, suit: Suit(rawValue: suit)!)
//println(card.simpleDescription())
deck += [card]
}
}
return deck
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
let deck = threeOfSpades.createDeck()
여기에 하나를 반복하고 enum
여러 값 유형을 제공 하는 데 사용하는 방법이 있습니다.enum
enum IterateEnum: Int {
case Zero
case One
case Two
case Three
case Four
case Five
case Six
case Seven
//tuple allows multiple values to be derived from the enum case, and
//since it is using a switch with no default, if a new case is added,
//a compiler error will be returned if it doesn't have a value tuple set
var value: (french: String, spanish: String, japanese: String) {
switch self {
case .Zero: return (french: "zéro", spanish: "cero", japanese: "nuru")
case .One: return (french: "un", spanish: "uno", japanese: "ichi")
case .Two: return (french: "deux", spanish: "dos", japanese: "ni")
case .Three: return (french: "trois", spanish: "tres", japanese: "san")
case .Four: return (french: "quatre", spanish: "cuatro", japanese: "shi")
case .Five: return (french: "cinq", spanish: "cinco", japanese: "go")
case .Six: return (french: "six", spanish: "seis", japanese: "roku")
case .Seven: return (french: "sept", spanish: "siete", japanese: "shichi")
}
}
//Used to iterate enum or otherwise access enum case by index order.
//Iterate by looping until it returns nil
static func item(index: Int) -> IterateEnum? {
return IterateEnum.init(rawValue: index)
}
static func numberFromSpanish(number: String) -> IterateEnum? {
return findItem { $0.value.spanish == number }
}
//use block to test value property to retrieve the enum case
static func findItem(predicate: ((_: IterateEnum) -> Bool)) -> IterateEnum? {
var enumIndex: Int = -1
var enumCase: IterateEnum?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = IterateEnum.item(index: enumIndex)
if let eCase = enumCase {
if predicate(eCase) {
return eCase
}
}
} while enumCase != nil
return nil
}
}
var enumIndex: Int = -1
var enumCase: IterateEnum?
// Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = IterateEnum.item(index: enumIndex)
if let eCase = enumCase {
print("The number \(eCase) in french: \(eCase.value.french), spanish: \(eCase.value.spanish), japanese: \(eCase.value.japanese)")
}
} while enumCase != nil
print("Total of \(enumIndex) cases")
let number = IterateEnum.numberFromSpanish(number: "siete")
print("siete in japanese: \((number?.value.japanese ?? "Unknown"))")
이것은 출력입니다.
프랑스어로 된 숫자 : zéro, 스페인어 : cero, 일본어 : nuru
프랑스어로 된 숫자 하나 : un, 스페인어 : uno, 일본어 : ichi
프랑스어에서 숫자 2 : deux, 스페인어 : dos, japanese : ni
숫자 프랑스어에서 3 : trois, 스페인어 : tres, japanese : san
프랑스어 4 번 : quatre, 스페인어 : cuatro, japanese : shi
5 번 프랑스어 : cinq, 스페인어 : cinco, japanese : go
숫자 6 번 프랑스어 : 6, 스페인어 : seis, japanese : roku
The number Seven in french : sept, spanish : siete, japanese : 시치
총 8 건
siete in japanese : 시치
최신 정보
최근에 열거를 처리하는 프로토콜을 만들었습니다. 프로토콜에는 Int raw 값을 가진 열거 형이 필요합니다.
protocol EnumIteration {
//Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil
static func item(index:Int) -> Self?
static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) {
static func findItem(predicate:((enumCase:Self)->Bool)) -> Self?
static func count() -> Int
}
extension EnumIteration where Self: RawRepresentable, Self.RawValue == Int {
//Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil
static func item(index:Int) -> Self? {
return Self.init(rawValue: index)
}
static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
if let eCase = enumCase {
item(index: enumIndex, enumCase: eCase)
}
} while enumCase != nil
completion?()
}
static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
if let eCase = enumCase {
if predicate(enumCase:eCase) {
return eCase
}
}
} while enumCase != nil
return nil
}
static func count() -> Int {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
} while enumCase != nil
//last enumIndex (when enumCase == nil) is equal to the enum count
return enumIndex
}
}
Swift 2.0
여기를 다루는 동안 내 제안은 다음 과 같습니다.
나는 원시 유형을 추가했습니다 Suit
enum
enum Suit: Int {
그때:
struct Card {
var rank: Rank
var suit: Suit
func fullDeck()-> [Card] {
var deck = [Card]()
for i in Rank.Ace.rawValue...Rank.King.rawValue {
for j in Suit.Spades.rawValue...Suit.Clubs.rawValue {
deck.append(Card(rank:Rank(rawValue: i)! , suit: Suit(rawValue: j)!))
}
}
return deck
}
}
@ Kametrixom과 마찬가지로 여기에 대답 하십시오. 당신이 등 수, 같은 배열의 케이크 모두에 액세스 할 수 있기 때문에 나는, 배열 AnySequence을 반환하는 것보다 더 나은 것 반환 믿는다
재 작성은 다음과 같습니다.
public protocol EnumCollection : Hashable {}
extension EnumCollection {
public static func allValues() -> [Self] {
typealias S = Self
let retVal = AnySequence { () -> AnyGenerator<S> in
var raw = 0
return AnyGenerator {
let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
return [S](retVal)
}
}
다른 해결책 :
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)
}
이것은 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)")
}
열거 형 toRaw()
과 fromRaw()
메소드가 있습니다. 따라서 원시 값이 인 Int
경우 처음부터 끝까지 반복 할 수 있습니다 enum
.
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()
여기에 내가 제안한 접근법이 있습니다. 완전히 만족 스럽지는 않지만 (Swift와 OOP에 익숙하지 않습니다!) 어쩌면 누군가가 그것을 다듬을 수 있습니다. 아이디어는 각 열거 같이 자신의 다양한 정보를 제공하는 것입니다 .first
및 .last
특성. 각 열거 형에 두 줄의 코드를 추가합니다. 여전히 약간 하드 코딩되어 있지만 적어도 전체 세트를 복제하지는 않습니다. Suit
열거 형을 Rank
열거 형이 아닌 Int 로 수정해야합니다 .
전체 솔루션을 에코하는 대신 .
다음은 case 문 뒤의 enum에 추가 한 코드입니다 ( Suit
enum은 유사합니다).
var first: Int { return Ace.toRaw() }
var last: Int { return King.toRaw() }
갑판을 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
}
속성이 열거 형이 아닌 요소와 관련되어 있기 때문에 불만족 스럽습니다. 그러나 'for'루프에 명확성을 추가합니다. Rank.first
대신에 말하고 싶습니다 Rank.Ace.first
. 모든 요소와 함께 작동하지만 추악합니다. 누군가 열거 형 수준으로 올리는 방법을 보여줄 수 있습니까?
그리고 그것을 작동시키기 위해 createDeck
카드 구조체 에서 방법을 들어 올렸습니다 . 해당 구조체에서 [String] 배열을 반환하는 방법을 알 수 없었습니다. 어쨌든 그러한 방법을 배치하기에는 나쁜 곳 인 것 같습니다.
나는 계산 된 속성을 사용하여 모든 값의 배열을 반환합니다 (이 게시물 http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ 덕분에 ). 그러나 int 원시 값도 사용하지만 열거 형의 모든 멤버를 별도의 속성으로 반복 할 필요는 없습니다.
업데이트 Xcode 6.1은를 사용하여 열거 형 멤버를 얻는 방법을 약간 변경 rawValue
했으므로 목록을 수정했습니다. 또한 먼저 잘못된 작은 오류를 수정했습니다 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++)
}
}
)
}
}
enum Rank: Int
{
case Ace = 0
case Two, Three, Four, Five, Six, Seve, Eight, Nine, Ten
case Jack, Queen, King
case Count
}
enum Suit : Int
{
case Spades = 0
case Hearts, Diamonds, Clubs
case Count
}
struct Card
{
var rank:Rank
var suit:Suit
}
class Test
{
func makeDeck() -> Card[]
{
let suitsCount:Int = Suit.Count.toRaw()
let rankCount:Int = Rank.Count.toRaw()
let repeatedCard:Card = Card(rank:Rank.Ace, suit:Suit.Spades)
let deck:Card[] = Card[](count:suitsCount*rankCount, repeatedValue:repeatedCard)
for i:Int in 0..rankCount
{
for j:Int in 0..suitsCount
{
deck[i*suitsCount+j] = Card(rank: Rank.fromRaw(i)!, suit: Suit.fromRaw(j)!)
}
}
return deck
}
}
Rick 답변을 기반으로 함 : 이것은 5 배 빠릅니다.
Count
사례를 추가하면 철저한 switch
구현 및 CaseIterable
준수 가 중단됩니다 .