iOS/Swift 공식문서

Enumerations

명언제조기벤제마 2022. 2. 16. 22:32

Enumeration Syntax

enum 키워드를 사용하여 열거형을 정의할 수 있다.

enum CompassPoint {
    case north
    case south
    case east
    case west
}

 

여러 case를 콤마로 구분하여 나열할 수 있다.

enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

 

note

Swift의 경우 열거형의 case들이 정수값을 가지지 않는다. 대신 case들은 해당 열거형 타입(ex. CompassPoint, Planet 등)으로 선언된 온전한 값이다.

 

각 열거형 정의는 새로운 타입을 정의한다. 따라서 Swift의 다른 타입처럼, 열거형의 이름은 대문자로 시작해야 한다. 아래 예시에서 directionToHead라는 변수는 타입 추론을 통해 CompassPoint 타입을 갖게 된다.

var directionToHead = CompassPoint.west

 

타입이 이미 정해진 이후에는 다음과 같이 타입을 생략할 수 있다.

directionToHead = .east

 

Matching Enumeration Values with a Switch Statement

열거형의 값을 switch문에서 사용할 수 있다. switch 문은 값의 모든 case를 다 포함해야 하기 때문에 열거형의 값 중 하나라도 빠져 있다면 컴파일되지 않는다.

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"

 

아래와 같이 여러 값들을 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

열거형 정의 시 CaseIterable 키워드를 사용하면 allCases 프로퍼티를 통하여 모든 값의 컬렉션을 사용할 수 있다. 이 경우 열거형은 CaseIterable 프로토콜을 따르게 된다.

enum Beverage: CaseIterable {
    case coffee, tea, juice
}

let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
// Prints "3 beverages available"

for beverage in Beverage.allCases {
    print(beverage)
}
// coffee
// tea
// juice

 

Associated Values

열거형의 각 case에 대하여 추가적인 정보를 저장할 수 있는데, 이 추가적인 정보를 관련 값(associated value)이라고 한다. 예를 들어 바코드가 4개의 정수값으로 이루어진 upc와, 문자들로 구성된 QR코드 2종류로 나뉜다면, 바코드를 다음과 같은 열거형으로 정의할 수 있다. 이와 같이 같은 타입이지만 다른 형태의 값을 가지는 case를 만들 수 있다.

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

 

UPC, QR코드는 아래와 같이 선언할 수 있다.

var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

 

관련 값은 switch case 문에서 상수/변수로 선언할 수 있다.

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

 

Raw Values

열거형의 case는 기존 타입의 raw 값을 가질 수 있다. case의 값은 모두 같은 타입이어야 한다.

enum ASCIIControlCharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}

 

Implicitly Assigned Raw Values

정수나 문자열을 raw 값으로 사용할 경우 각 case에 대하여 명시적으로 raw 값을 할당할 필요가 없다. 정수를 raw 값으로 사용하는 경우 각 case의 암시적 값은 이전 case 값보다 1만큼 큰 값이다. 첫번째 case의 경우 값을 명시하지 않으면 0으로 설정된다.

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

 

문자열이 사용될 경우, 각 case 이름의 문자열이 raw 값이 된다. raw 값은 rawValue 프로퍼티로 접근할 수 있다.

enum CompassPoint: String {
    case north, south, east, west
}

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"

 

Initializing from a Raw Value

열거형을 raw 값으로 정의한 경우, raw 값으로 사용한 타입의 값을 받는 initializer를 사용할 수 있다. 해당 값을 가지는 case가 존재하면 해당 case를 반환하고, 없으면 nil을 반환한따. nil을 반환할 수 있기 때문에 타입은 optional이다. case를 반환하지 못할 수 있기 때문에 failable initializer라고 부른다.

let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.uranus

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

 

Recursive Enumerations

최소 한 개의 case에서 관련 값으로 다른 열거형 인스턴스를 가지는 열거형을 말한다. 해당 caseindirect라는 키워드를 적어서 재귀적인 case임을 나타낸다.

enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

 

모든 case에 indirect 표시를 하고 싶으면 enum 키워드 앞에 indirect 키워드를 적는 방법도 있다.

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, 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"

 

Reference

https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html