Enumerations

Groot·2022년 6월 27일
0

Swift Language Guide

목록 보기
9/24
post-thumbnail

Enumerations

  • 열거형은 관련 값 그룹에 대한 공통 유형을 정의하고 코드 내에서 유형이 안전한 방식으로 해당 값으로 작업할 수 있도록 합니다.
  • Swift의 열거형은 훨씬 더 유연하며 열거형의 각 경우에 값을 제공할 필요가 없습니다.
  • 각 열거 케이스에 대해 값(원시 값이라고 함)이 제공되는 경우 값은 문자열, 문자 또는 정수 또는 부동 소수점 유형의 값일 수 있습니다.
  • 열거형 케이스는 다른 언어에서 공용체 또는 변형이 하는 것처럼 각 다른 케이스 값과 함께 저장할 모든 유형의 관련 값을 지정할 수 있습니다.
  • Swift의 열거형은 그 자체로 일급 유형입니다.
  • 열거형의 현재 값에 대한 추가 정보를 제공하는 계산 프로퍼티와 열거형이 나타내는 값과 관련된 기능을 제공하는 인스턴스 메서드 같이 전통적으로 클래스에서만 지원되는 많은 기능을 채택합니다
  • 열거형은 초기 케이스 값을 제공하기 위해 이니셜라이저를 정의할 수도 있습니다.
  • 원래 구현을 넘어 기능을 확장하도록 확장될 수 있습니다.
  • 표준 기능을 제공하기 위해 프로토콜을 준수할 수 있습니다.

📌 Enumeration Syntax

  • enum 키워드를 사용하여 열거를 도입하고 전체 정의를 중괄호 한 쌍 안에 배치합니다.
    enum SomeEnumeration {
        // enumeration definition goes here
    }
  • 다음은 나침반의 네 가지 주요 점에 대한 예입니다.
    enum CompassPoint {
        case north
        case south
        case east
        case west
    }

    Swift 열거형 케이스에는 C 및 Objective-C와 같은 언어와 달리 기본적으로 정수 값이 설정되어 있지 않습니다. 위의 CompassPoint 예에서 북쪽, 남쪽, 동쪽 및 서쪽은 암시적으로 0, 1, 2 및 3과 같지 않습니다. 대신, 다른 열거 케이스는 명시적으로 정의된 유형의 CompassPoint와 함께 고유한 값입니다.

  • 여러 케이스가 쉼표로 구분되어 한 줄에 나타날 수 있습니다.
    enum Planet {
        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
    }
  • 각 열거 정의는 새 유형을 정의합니다. Swift의 다른 유형과 마찬가지로 해당 이름(예: CompassPoint 및 Planet)은 대문자로 시작합니다. 열거형에 복수형이 아닌 단수형 이름을 지정하여 자명하게 읽히도록 합니다.
    var directionToHead = CompassPoint.west
  • directionToHead의 유형은 CompassPoint의 가능한 값 중 하나로 초기화될 때 유추됩니다.
  • directionToHead가 CompassPoint로 선언되면 더 짧은 점 구문을 사용하여 다른 CompassPoint 값으로 설정할 수 있습니다.
    directionToHead = .east
  • directionToHead의 유형은 이미 알려져 있으므로 값을 설정할 때 유형을 삭제할 수 있습니다. 이렇게 하면 명시적으로 입력된 열거형 값으로 작업할 때 가독성이 높은 코드가 됩니다.

📌 Matching Enumeration Values with a Switch Statement

  • 개별 열거 값을 switch 문과 일치시킬 수 있습니다.
    directionToHead = .south
    switch directionToHead {
    case .north:
        print("Lots of planets have a north")
    case .south:
        print("Watch out for penguins")
    case .east:
        print("Where the sun rises")
    case .west:
        print("Where the skies are blue")
    }
    // Prints "Watch out for penguins"
  • 제어 흐름에 설명된 대로 switch 문은 열거형의 경우를 고려할 때 철저해야 합니다.
  • .west에 대한 사례가 생략되면 이 코드는 CompassPoint 사례의 전체 목록을 고려하지 않기 때문에 컴파일되지 않습니다.
  • exhaustiveness을 요구하면 열거형 케이스가 실수로 생략되지 않도록 합니다.
  • 모든 열거 사례에 대해 사례를 제공하는 것이 적절하지 않은 경우 명시적으로 해결되지 않은 사례를 포함하는 default를 제공할 수 있습니다.
    let somePlanet = Planet.earth
    switch somePlanet {
    case .earth:
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
    }
    // Prints "Mostly harmless"

📌 Iterating over Enumeration Cases

  • 일부 열거의 경우 해당 열거의 모든 경우를 collection으로 쓰는 것이 유용합니다.
  • 열거형 이름 뒤에 CaseIterable Protocol을 작성하여 활성화합니다.
  • Swift는 모든 케이스의 컬렉션을 열거형의 allCases 속성으로 노출합니다.
    enum Beverage: CaseIterable {
        case coffee, tea, juice
    }
    let numberOfChoices = Beverage.allCases.count
    print("\(numberOfChoices) beverages available")
    // Prints "3 beverages available"
  • 위의 예에서 Beverage.allCases를 작성하여 Beverage 열거형의 모든 사례를 포함하는 컬렉션에 액세스합니다.
  • 다른 컬렉션과 마찬가지로 allCases를 사용할 수 있습니다. 컬렉션의 요소는 열거 유형의 인스턴스이므로 이 경우에는 Beverage 값입니다.
  • 위의 예는 얼마나 많은 케이스가 있는지 계산하고, 아래의 예는 for-in 루프를 사용하여 모든 케이스를 반복합니다.
    for beverage in Beverage.allCases {
        print(beverage)
    }
    // coffee
    // tea
    // juice

📌 Associated Values

  • 이전 섹션의 예는 열거형의 경우가 자체적으로 정의된(및 형식화된) 값인 방법을 보여줍니다.
  • 이러한 케이스 값과 함께 다른 유형의 값을 저장할 수 있는 것이 유용합니다.
  • 이 추가 정보를 Associated Values이라고 하며 해당 대소문자를 코드에서 값으로 사용할 때마다 달라집니다.
  • Swift에서 두 유형의 제품 바코드를 정의하는 열거형은 다음과 같습니다.
    enum Barcode {
        case upc(Int, Int, Int, Int)
        case qrCode(String)
    }
  • 이 정의는 실제 Int 또는 String 값을 제공하지 않습니다. Barcode 상수 및 변수가 Barcode.upc 또는 Barcode.qrCode와 같을 때 저장할 수 있는 관련 값의 유형만 정의합니다.
  • 그런 다음 다음 유형 중 하나를 사용하여 새 바코드를 만들 수 있습니다.
    var productBarcode = Barcode.upc(8, 85909, 51226, 3)
  • 이 예에서는 productBarcode라는 새 변수를 만들고 연결된 튜플 값이 (8, 85909, 51226, 3)인 Barcode.upc 값을 할당합니다.
  • 동일한 제품에 다른 유형의 바코드를 할당할 수 있습니다.
    productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
  • 이 시점에서 원래 Barcode.upc 및 해당 정수 값은 새 Barcode.qrCode 및 해당 문자열 값으로 대체됩니다.
  • 바코드 유형의 상수 및 변수는 .upc 또는 .qrCode(관련 값과 함께)를 저장할 수 있지만 주어진 시간에 하나만 저장할 수 있습니다.
  • 열거형 값을 Switch 문과 일치의 예와 유사한 switch 문을 사용하여 다양한 바코드 유형을 확인할 수 있습니다
  • 그러나 이번에는 연결된 값이 switch 문의 일부로 추출됩니다. 연결된 각 값을 스위치 케이스의 본문 내에서 사용하기 위해 상수(let 접두사 포함) 또는 변수(var 접두사 포함)로 추출합니다.
    switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
        print("QR code: \(productCode).")
    }
    // Prints "QR code: ABCDEFGHIJKLMNOP."
  • 열거 케이스에 대한 모든 관련 값이 상수로 추출되거나 모두 변수로 추출되는 경우 간결함을 위해 케이스 이름 앞에 단일 var 또는 let 주석을 배치할 수 있습니다.
    switch productBarcode {
    case let .upc(numberSystem, manufacturer, product, check):
        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
    case let .qrCode(productCode):
        print("QR code: \(productCode).")
    }
    // Prints "QR code: ABCDEFGHIJKLMNOP."

📌 Raw Values

  • 연결된 값의 바코드 예제는 열거형의 사례가 서로 다른 유형의 연결된 값을 저장한다고 선언할 수 있는 방법을 보여줍니다.
  • 연결된 값의 대안으로 열거형 케이스는 모두 동일한 유형인 기본값(원시 값이라고 함)으로 미리 채워질 수 있습니다.
    enum ASCIIControlCharacter: Character {
        case tab = "\t"
        case lineFeed = "\n"
        case carriageReturn = "\r"
    }
  • 원시 값은 문자열, 문자 또는 정수 또는 부동 소수점 숫자 유형일 수 있습니다. 각 원시 값은 열거 선언 내에서 고유해야 합니다.

    원시 값은 연결된 값과 동일하지 않습니다. 원시 값은 위의 세 ASCII 코드와 같이 코드에서 열거를 처음 정의할 때 미리 채워진 값으로 설정됩니다. 특정 열거 케이스의 원시 값은 항상 동일합니다. 연결된 값은 열거형의 경우 중 하나를 기반으로 새 상수 또는 변수를 생성할 때 설정되며 그렇게 할 때마다 다를 수 있습니다.

📍 Implicitly Assigned Raw Values

  • 정수 또는 문자열 원시 값을 저장하는 열거로 작업할 때 각 경우에 원시 값을 명시적으로 할당할 필요가 없습니다.

  • 그렇지 않으면 Swift가 자동으로 값을 할당합니다.

  • 예를 들어 정수가 원시 값에 사용되는 경우 각 경우에 대한 암시적 값은 이전 사례보다 하나 더 많습니다. 첫 번째 경우에 값이 설정되지 않은 경우 해당 값은 0입니다.

    enum Planet: Int {
        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    }
  • 위의 예에서 Planet.mercury는 1의 명시적 원시 값을 갖고 Planet.venus는 2의 Implicitly Assigned Raw Values를 갖는 식입니다.

  • 문자열이 원시 값에 사용되는 경우 각 케이스의 암시적 값은 해당 케이스 이름의 텍스트입니다.

    enum CompassPoint: String {
        case north, south, east, west
    }
  • 위의 예에서 CompassPoint.south는 "south" 등의 암시적 원시 값을 갖습니다.

  • rawValue 속성을 사용하여 열거형 케이스의 원시 값에 액세스합니다.

    let earthsOrder = Planet.earth.rawValue
    // earthsOrder is 3
    
    let sunsetDirection = CompassPoint.west.rawValue
    // sunsetDirection is "west"

📍 Initializing from a Raw Value

  • 원시 값 유형으로 열거형을 정의하면 열거형은 원시 값 유형의 값(rawValue라는 매개변수로)을 취하고 열거형 케이스 또는 nil을 반환하는 이니셜라이저를 자동으로 수신합니다.

  • 이 이니셜라이저를 사용하여 열거형의 새 인스턴스를 만들 수 있습니다.

    let possiblePlanet = Planet(rawValue: 7)
    // possiblePlanet is of type Planet? and equals Planet.uranus
  • 그러나 가능한 모든 Int 값이 일치하는 행성을 찾는 것은 아닙니다.

  • 이 때문에 원시 값 이니셜라이저는 항상 optional 열거 케이스를 반환합니다.

  • 위의 예에서 possiblePlanet은 Planet? 또는 "optional Planet" 유형입니다.

    모든 원시 값이 열거형 케이스를 반환하는 것은 아니기 때문에 원시 값 이니셜라이저는 실패할 수 있는 이니셜라이저입니다.

    et positionToFind = 11
    if let somePlanet = Planet(rawValue: positionToFind) {
        switch somePlanet {
        case .earth:
            print("Mostly harmless")
        default:
            print("Not a safe place for humans")
        }
    } else {
        print("There isn't a planet at position \(positionToFind)")
    }
    // Prints "There isn't a planet at position 11"
  • 이 예제는 Optional Binding을 사용하여 원시 값이 11인 행성에 액세스하려고 시도합니다.

  • if let somePlanet = Planet(rawValue: 11) 문은 Optional Planet을 만들고 검색할 수 있는 경우 somePlanet을 해당 Optional Planet의 값으로 설정합니다.

  • 이 경우 위치가 11인 행성을 검색할 수 없으므로 대신 else 분기가 실행됩니다.


📌 Recursive Enumerations

  • 재귀 열거형은 열거형의 다른 인스턴스를 하나 이상의 열거형 케이스에 대한 연관값으로 갖는 열거형입니다.

  • 열거형 케이스가 재귀적임을 나타내기 위해 indirect를 사용해서 컴파일러에게 필요한 간접 참조 계층을 삽입하도록 지시합니다.

    enum ArithmeticExpression {
        case number(Int)
        indirect case addition(ArithmeticExpression, ArithmeticExpression)
        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
    }
  • 열거형 시작 전에 indirect을 작성하여 관련 값이 있는 열거형의 모든 경우에 대해 간접 참조를 활성화할 수도 있습니다.

    indirect enum ArithmeticExpression {
        case number(Int)
        case addition(ArithmeticExpression, ArithmeticExpression)
        case multiplication(ArithmeticExpression, ArithmeticExpression)
    }
  • 이 열거형은 세 가지 종류의 산술 표현식(일반 숫자, 두 표현식의 덧셈, 두 표현식의 곱셈)을 저장할 수 있습니다.

  • 더하기 및 곱하기 사례에는 산술 표현식이기도 한 연관된 값이 있습니다.

  • 이러한 연관된 값을 사용하면 표현식을 중첩할 수 있습니다.

  • 예를 들어, (5 + 4) * 2 표현식은 곱셈의 오른쪽에 숫자가 있고 곱셈의 왼쪽에 다른 표현식이 있습니다.

  • 데이터가 중첩되어 있기 때문에 데이터를 저장하는 데 사용되는 열거형도 중첩을 지원해야 합니다.

  • 즉, 열거형은 재귀적이어야 합니다.

  • 아래 코드는 (5 + 4) * 2에 대해 생성되는 ArithmeticExpression 재귀 열거를 보여줍니다.

    let five = ArithmeticExpression.number(5)
    let four = ArithmeticExpression.number(4)
    let sum = ArithmeticExpression.addition(five, four)
    let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
  • 재귀 함수는 재귀 구조를 가진 데이터로 작업하는 간단한 방법입니다. 예를 들어, 다음은 산술 표현식을 평가하는 함수입니다.

    func evaluate(_ expression: ArithmeticExpression) -> Int {
        switch expression {
        case let .number(value):
            return value
        case let .addition(left, right):
            return evaluate(left) + evaluate(right)
        case let .multiplication(left, right):
            return evaluate(left) * evaluate(right)
        }
    }
    
    print(evaluate(product))
    // Prints "18"
  • 이 함수는 단순히 관련 값을 반환하여 일반 숫자를 평가합니다.

  • 좌변 식을 평가하고 우변 식을 평가한 다음 더하거나 곱하여 덧셈 또는 곱셈을 평가합니다.

profile
I Am Groot

0개의 댓글