enum 키워드, 각 enum case 에는 case keyword
enum CompassPoint {
case north
case south
case east
case west
}
// 한 줄에 표시 가능
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
swift 의 enum 은 기본적으로 int value 를 갖고 있지 않음 (C, Objc 는 있음). Enum Type 이름은 복수형보다는 단수형을 써서 독립적으로도 읽힐 수 있게 만들기
var directionToHead = CompassPoint.west
// 한 번 선언된 후에는 dot syntax 로 다른 값에 할당 가능
directionToHead = .east
switch 문으로 개별 enum 값을 매칭할 수 있음
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 문은 exhaustive 해야 하기 때문에 명시적으로 언급 안 된 case 가 있는 경우 default 제공
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// Prints "Mostly harmless".
: CaseIterable 을 통해 모든 case 의 collection 을 만들고, allCases property 로 collection 에 접근
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 value 를 사용해서 case 값에 추가로 다른 값을 저장할 수 있음
Swift enum 에 타입 상관 없이 associated value 를 저장할 수 있고, 각 case 마다 value type 을 달라질 수 있음.
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch 문에서 associated value 는 switch 문의 일부로 추출됨. 각 associated value 를 상수 / 변수로 할당 가능.
case 의 모든 associated value 가 상수/변수로 추출되는 경우 하나의 let / var 를 case 이름 전에 붙여서 간결하게 표현 가능
오직 한 case 만 matching 하는 경우 if-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."
// 간결 버전
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."
if case .qrCode(let productCode) = productBarcode {
print("QR code: \(productCode).")
}
Enum case 는 기본값으로 생성될 수 있음 (무조건 다 같은 type 이어야 함)
각 raw value 는 enum 내에서 고유해야 함
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
Int, 문자열을 저장하는 enum 인 경우 명시적으로 각 case 에 raw value 를 지정하지 않아도 Swift 가 자동으로 값을 할당함
Int 의 경우 각 case 는 이전 case 보다 1 증가한 값이고, 첫 번째 값이 설정되지 않은 경우 0임
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
string 이 raw value 인 경우 각 암묵적 value 는 case 의 이름
enum CompassPoint: String {
case north, south, east, west
}
Raw value 를 갖는 enum 을 정의한 경우 자동으로 raw value type 의 값을 받는 initializer 를 가짐. Initializer 는 enum case / nil 을 리턴함.
매칭되는 raw value 를 찾을 수 없는 경우를 대비해 raw value initializer 는 optional enum case 를 리턴함 (failable initializer)
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.uranus
Associated value 로 자기 자신 enum 인스턴스를 갖는 enum. indirect 를 써서 enum 이 recursive 함을 명시해서 compiler 가 indirection 을 위한 필요한 layer 를 삽입할 수 있게 함
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
Recursive 가 문제가 되는 이유? Swift enum 은 value type 인데 compile time 에 size 를 알아야 함. 그래서
indirect키워드를 통해 Swift 에게 해당 recursive 한 부분을 reference 로 사용하게끔 하는 것. 해당 reference 를 heap 에 저장. e.g. number -> fixed size. addition -> 두 개의 pointer (fixed size)
// e.g. (5 + 4) * 2
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))