-
열거형 (Enumerations)Swift 2019. 6. 26. 01:34728x90
열거형 (Enumerations)
열거형은 관련된 값으로 이루어진 그룹을 공통의 형(type)으로 선언해 형 안정성(type-safety)을 보장하는 방법으로 코드를 다룰 수 있게 해줍니다.
C나 Objective-C에 익숙하시다면 Integer 값들로 열거형을 구성한 것을 보실 수 있는데요, Swift는 case값이 String, Character, Integer, floating 값들을
열거형 문법 (Enumeration Syntax)
예를들어, 계산기의 연산자들을 모은
CalculationOperator
가 있을 수 있겠죠.enum CalculationOperator { case plus case minus case division case multiple case eqaul }
Swift의 열거형은 생성될 때 각 case 별로 기본 integer 값을 할당하지 않습니다. 위
CalculationOperator
는 각각 암시적으로 0, 1, 2, 3, 4 값을 갖지 않고 CalculationOperator로 선언된 온전한 값이에요.여러 case 를 (,)로 구분해 한줄로 적을 수도 있습니다.
enum CalculationOperator { case plus, minus, division, multiple, eqaul }
열거형은 완전히 새로운 형을 하나 새로 만드는 것이기 때문에 대문자로 시작해야 합니다.
var calOperator = CalculationOperator.plus
타입이 정해지면 축약형 문법을 사용할 수도 있어요. calOperator의 타입은 초기화때 추론되었기 때문에 축약형으로 사용할 수 있습니다.
calOperator = .minus
Swift 구문에서 열거형 값 매칭하기 (Matching Enumeration Values with a Switch Statement)
각 열거형 값을 Switch 문에서 매칭할 수 있습니다.
calOperation = .plus switch calOperation { case: .plus: return a+b case: .minus: return a-b case: .division: return a/b case: .multiple: return a*b case: .equal: return a }
Switch 문은 반드시 모든 case를 완전히 포함해야 해요. 위의 예에서 equal이 빠지면 컴파일 되지 않습니다. 만약 적당하지 않다면 default를 사용해 처리해줘야 합니다.
반복문에서 enum 사용하기 (Iterating over Enumeration Cases)
enum의 모든 case의 집합은 반복문에서 매우 유용하게 사용될 수 있겠죠?
:CaseIterable
를 사용하면allCases
를 사용할 수 있습니다.enum Beverage: CaseIterable { case coffee, tea, juice } let numberOfChoices = Beverage.allCases.count print("\(numberOfChoices) beverages available") // Prints "3 beverages available"
위 예에서 Berverage.allCases 는 일반 배열처럼 사용가능합니다. 당연히 내부 요소는 Beverage 타입이겠죠?
for beverage in Beverage.allCases { print(beverage) } // coffee // tea // juice
관련 값 (Associated Values)
필요하다면 열거형의 각 case의 타입이 다르게 할 수 있습니다.
예를 들어, 위와 같이 4가지 숫자로 구분된 종류가 있거나, 2,953개의 문자로 구성된 QR코드 형태로 이루어진 두 종류가 있다면, 바코드를 다음과 같이 열거형으로 정의할 수 있습니다.
enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) }
관련 값 (Associated Values) 을 이용하면 위와같이 같은 형 (Barcode) 이지만, 다른 형태의 값을 갖는 case를 만들 수 있습니다.
바코드는 다음과 같이 선언할 수 있고
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."
case 안의 관련 값이 전부 상수이거나 변수라면 앞으로 빼서 선언할 수 있습니다.
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 값 (Raw Values)
관련 값 (Associated Values) 의 대안으로 모두 동일한 타입의 기본값(raw values) 으로 채워질 수 있습니다.
아래는 raw value 로 ASCII 값을 저장하는 예 입니다.
enum ASCIIControlCharacter: Character { case tab = "\t" case lineFeed = "\n" case carriageReturn = "\r" }
위의 예에서처럼 Character 이외에도 String, Integer, Float 등의 형을 사용할 수도 있습니다. 단, 각 raw 값은 열거형 선언에서 유일한 값으로 중복되면 안됩니다.
암시적으로 할당된 Raw 값 (Implicitly Assigned Raw Values)
각 case 별로 명시적으로 raw 값을 할당할 필요는 없습니다.
enum Planet: Int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune }
위 경우는 mercury에 1을 raw 값으로 명시적으로 할당했고 나머지는 venus = 2, earth = 3 등으로 자동으로 raw 값을 갖습니다.
만약 String 을 raw 값으로 사용한다면 자동으로 case 텍스트를 raw값으로 갖습니다.
enum CompassPoint: String { case north, south, east, west }
위 경우 CompassPoint.south는 암시적으로 "south" 를 raw 값으로 갖습니다.
raw 값은 rawValue 프로퍼티를 사용해 접근할 수 있습니다.
let earthsOrder = Planet.earth.rawValue // earthsOrder is 3 let sunsetDirection = CompassPoint.west.rawValue // sunsetDirection is "west"
Raw 값을 이용한 초기화 (Initializing from a Raw Value)
raw 값을 이용해 열거형 변수를 초기화 할 수 있습니다.
let possiblePlanet = Planet(rawValue: 7) // possiblePlanet is of type Planet? and equals Planet.uranus
raw 값 초기자는 모든 raw 값에 대해 열거형 case 반환이 보장되지 않으므로 실패할 수 있는 failable initializer 입니다.
만약 raw 값이 없는 값으로 초기자를 지정하면 nil이 됩니다.
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)
재귀 열거자는 다른 enum 인스턴스를 관계 값으로 갖는 열거형 입니다. 재귀 열거자 case는 앞에
indirect
키워드를 붙여 표시합니다.enum ArithmeticExpression { case number(Int) indirect case addition(ArithmeticExpression, ArithmeticExpression) indirect case multiplication(ArithmeticExpression, ArithmeticExpression) }
만약 모든 case에
indirect
를 표시하고 싶으면 enum 키워드 앞에 표시하면 됩니다.indirect enum ArithmeticExpression { case number(Int) case addition(ArithmeticExpression, ArithmeticExpression) case multiplication(ArithmeticExpression, ArithmeticExpression) }
아래 예제는 ( 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))
다음은 위 재귀 열거자를 처리하는 함수 입니다.
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"
'Swift' 카테고리의 다른 글
KVO(Key-Value-Observing) (0) 2019.09.20 Swift) 배열의 중복체크 (0) 2019.07.25 Swift) 소수점 다루기 (0) 2019.07.22 Swift) 스위프트에서 '모든 것은 객체다' (1) 2019.07.02 Swift) 집합 (Set) (0) 2019.05.18