programing

문자열 형식으로 열거하는 방법

fastcode 2023. 4. 10. 22:19
반응형

문자열 형식으로 열거하는 방법

enum Suit: String {
    case spades = "♠"
    case hearts = "♥"
    case diamonds = "♦"
    case clubs = "♣"
}

예를 들어 다음과 같은 작업을 수행할 수 있습니다.

for suit in Suit {
    // do something with suit
    print(suit.rawValue)
}

결과 예:

♠
♥
♦
♣

이 투고는 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
}

Swift 4.2 이상

Swift 4.2(Xcode 10 포함)부터는 프로토콜 준수를 에 추가하면 이점을 얻을 수 있습니다.이 프로토콜 준수를 추가하려면 다음과 같이 작성하기만 하면 됩니다.

extension Suit: CaseIterable {}

enum이 사용자 고유의 경우 선언에서 직접 적합성을 지정할 수 있습니다.

enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }

그러면 다음 코드가 가능한 모든 값을 인쇄합니다.

Suit.allCases.forEach {
    print($0.rawValue)
}

이전 Swift 버전(3.x 및 4.x)과의 호환성

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

를 만들었습니다.iterateEnum()인 경우를 위해.enumtypes.timeout.

다음은 사용 예를 제시하겠습니다.

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관련 유형이 있는 s는 사례의 수가 다음과 같은 경우에 대한 지표일 뿐이다.2...256 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .UInt8의 경우, 삭제257...65536은 ,,,,,,,,입니다.UInt16'아까', '아까', '아까', 이렇게 할 수 있어요.unsafeBitcast대응하는 부호 없는 정수 타입으로부터 송신됩니다.
  • .hashValue.enum of、 of the 、 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
    }
}

Swift 3.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
    }
}

다른 솔루션은 작동하지만 모두 가능한 등급과 등급의 수, 또는 첫 번째와 마지막 등급에 대해 가정합니다.사실, 카드 한 벌의 레이아웃은 아마도 가까운 미래에 크게 바뀌지 않을 것이다.그러나 일반적으로 가능한 한 추측을 적게 하는 코드를 작성하는 것이 좋습니다.솔루션:

는 생 를 생 활자에 Suitenum을 enum을 할 수 .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:)는 장애 가능성이 있는 이니셜라이저로, 임의의 값을 반환합니다. 두 으로써, 그 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()

나는 우연히 몇 바이트를 찾아 @rintaro의 대답과 매우 유사한 작업을 나중에 알게 되었다.사용법은 다음과 같습니다.

enum E : EnumCollection {
    case A, B, C
}

Array(E.cases())    // [A, B, C]

주목할 만한 점은 관련 값이 없는 열거형에서 사용할 수 있다는 것입니다.케이스가 없는 Enum에는 이 기능이 작동하지 않습니다.

@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이치노

할 수 .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
}

이 문제는 이제 훨씬 쉬워졌다.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 이전:

저는 "List qureption in Swift"를 찾아서 정리한 이 솔루션이 마음에 듭니다.

Strings 대신 Int raws를 사용하지만 두 번 입력하는 것을 피하고 범위를 커스터마이즈할 수 있으며 raw 값을 하드 코드하지 않습니다.

이것은 원래 솔루션의 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의 경우 raw 값 할당을 사용하지 않는 경우를 가정하여 원칙적으로 이 방법을 사용할 수 있습니다.

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

이제 Enum을 생성할 때마다(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())

simpleDescription보다 표준적인 CustomStringConvertible 프로토콜을 사용하면 다음과 같습니다.

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 4.2/Swift 5

enum Suit: String, CaseIterable {
   case spades = "♠"
   case hearts = "♥"
   case diamonds = "♦"
   case clubs = "♣"
}

질문에 따라 출력에 액세스하려면:

for suitKey in Suit.allCases {
    print(suitKey.rawValue)
}

출력:

♠
♥
♦
♣

CaseIterable:에 모든 값의 컬렉션을 나타냅니다.CaseItable 프로토콜을 준수하는 유형은 일반적으로 연결된 값이 없는 열거형입니다.CaseItable 유형을 사용하는 경우 유형의 allCases 속성을 사용하여 유형의 모든 케이스 모음에 액세스할 수 있습니다.

케이스 액세스에는 .allCases를 사용합니다.상세한 것에 대하여는, https://developer.apple.com/documentation/swift/caseiterable 를 클릭해 주세요.

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

Swift 2.2 폼으로 업데이트된 코드 @Kametrixom의 답변

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

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

Xcode 10 (Swift 4.2 탑재)

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)

인쇄:

['급여', '경험', '테크놀로지', '활용되지 않음', '활용되지 않음', '활용되지 않음'


이전 버전

★★★의 enumInt

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]


★★★의 enumString

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)

인쇄:

['급여', '경험', '테크놀로지', '활용되지 않음', '활용되지 않음', '활용되지 않음'

있는 .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"]

편집: Swift Evolution Proposal SE-0194 Derived Collection of Enum Cases는 이 문제에 대한 수준 높은 솔루션을 제안합니다.Swift 4.2 이상에서 볼 수 있습니다.이 제안서는 이미 여기에 언급된 것과 유사한 몇 가지 회피책도 지적하고 있지만 그럼에도 불구하고 흥미로운 결과를 얻을 수 있을 것이다.

저도 완벽을 위해 원래 자리를 지킬 거예요.


이는 Swift 3에 맞게 조정된 @Peymmankh의 답변에 기초한 또 다른 접근법이다.

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]

에 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의 새로운 기능).

편집: 소문자 camel Case가 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, 듣고 있니?!)

실험은 다음과 같습니다: EXPERIMENT

랭크와 슈트의 조합별로 1장의 카드로 풀덱의 카드를 작성하는 방법을 카드에 추가합니다.

따라서 메서드를 추가하는 것 외에 지정된 코드를 수정하거나 개선하지 않고(또한 아직 가르치지 않은 것을 사용하지 않고) 이 솔루션을 생각해 냈습니다.

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

출력은 다음과 같습니다.

0 일본어: 랑:0: cero, nuru
: 스페인어 : 일본어 : 랑위위1 : un, o un : uno, 본 : ichi
는 프랑스어: 일본어: ni 랑:::2: dux, dos, ni
: 일본어: 3 은 tro은: trois, 페 t: tres, 본: san
자는4 는는는는 、 shi 。
5: go 5: cinq, cinco, go: go
6: 6, 6: 6, seis, roku
7: sept, 7: sept, siete: sichi

총 8건

siete(일본어): sichi


갱신하다

최근에 열거를 처리하는 프로토콜을 만들었습니다.프로토콜에는 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
    }
}

해킹처럼 보이지만 원시 값을 사용하면 다음과 같은 작업을 수행할 수 있습니다.

enum Suit: Int {  
    case Spades = 0, Hearts, Diamonds, Clubs  
 ...  
}  

var suitIndex = 0  
while var suit = Suit.fromRaw(suitIndex++) {  
   ...  
}  

Swift 2.0은 다음과 .

raw에 했습니다.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: How do I get a Swift enum?의 새로운 기능을 사용하는 솔루션이 있습니다.


이 스레드에는 좋은 해결책이 많이 있지만, 그 중 일부는 매우 복잡합니다.나는 가능한 한 단순화하는 것을 좋아한다.여기에서는, 다양한 요구에 대응할 수도 있고, 그렇지 않을 수도 있습니다만, 대부분의 경우 효과가 있다고 생각합니다.

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

에는 enum이 있습니다.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()
    }
}

는 1을 입니다.simpleDescription했습니다.convertedSuit를 정하다, 정수를 .convertedSuit.simpleDescription()

제가 제안하는 접근방식은 다음과 같습니다.완전히 만족스럽지는 않지만(Swift와 OOP는 처음입니다!) 누군가 개선해 줄 수 있을지도 모릅니다.마다 독자적인 하도록 하는 입니다..first ★★★★★★★★★★★★★★★★★」.last에는 은 조금 적어도되지 않습니다.각 열거형에는 두 줄의 코드만 추가됩니다. 아직 약간 하드 코딩되어 있지만 적어도 전체 집합은 복제되지 않았습니다. 경우 반드시 필요합니다.Suit은 enum과 .Rankuntype.enum이 untype입니다.

전체 것이 '반향하다', '반향하다', '반향하다', '반향하다'에., 대enum(enum, "num")Suit enum은 "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
}

속성이 열거형이 아닌 요소와 연관되어 있기 때문에 만족스럽지 않습니다.찬성하다라고 Rank.firstRank.Ace.first(어떤 요소에서도) 동작하지만, 보기 흉합니다.누가 어떻게 그것을 열거형 수준으로 끌어올릴 수 있는지 보여줄 수 있나요?

그리고 그걸 작동시키기 위해createDeck이치노이 구조에서 [String] 어레이를 반환하는 방법을 알 수 없었습니다.어쨌든 그런 방법을 사용하는 것은 좋지 않은 것 같습니다.

모든 값의 배열을 반환하는 계산 속성을 사용했습니다(이 게시물 http://natecook.com/blog/2014/10/loopy-random-enum-ideas/)).단, int raw 값도 사용하지만 열거의 모든 멤버를 별도의 속성으로 반복할 필요는 없습니다.

UPDATE Xcode 6.1을 사용하여 Enum 멤버를 가져오는 방법이 약간 변경되었습니다.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++)
                }
            }
        )
    }
}

언급URL : https://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type

반응형