Enumerations
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
에서 관련 값으로 다른 열거형 인스턴스를 가지는 열거형을 말한다. 해당 case
는 indirect
라는 키워드를 적어서 재귀적인 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