안녕하세요! 릴리입니다🙋🏻♀️
오늘은 Swift Language Guide의 Enumerations 파트를 읽어보고 공부해보도록 하겠습니다👍
포스팅 내용에 대한 질문이나 피드백은 언제나 환영입니다!
스위프트의 열거형은 연관된 값들을 그룹으로 묶어서 일반 타입으로 정의한 후 사용할 수 있도록합니다. raw value(원시값)로 Integer타입만 저장할 수 있는 C의 열거형과는 달리 스위프트의 열거형은 string, character, integer, floating-point type도 raw value도 사용할 수 있습니다.
열거형은 first-class type(일급 객체)이기 때문에 class에서 지원하는 많은 특징들을 채택하고 있습니다. 예를 들어서 연산 프로퍼티, 인스턴스 메서드, 이니셜라이저 정의 가능, 프로토콜 준수 가능한 특징들이 있습니다.
열거형은 enum 키워드로 정의합니다. enum 키워드 오른쪽에 타입의 이름을 적어주고, 괄호 안에 타입안에 속하게 될 case들을 정의해줍니다. 타입 이름은 대문자로 시작하고, 단수형으로 적어줍니다.
enum SomeEnumeration {
// enumeration definition goes here
}
enum CompassPoint {
case north
case south
case east
case west
}
이렇게 정의된 CompassPiont는 새로운 하나의 타입이 됩니다.
위 예시 처럼 하나의 주제로 묶을 수 있는 연관된 값들을 타입으로 정의하고, 관리하고 싶을 때 유용하게 쓰일 수 있을 것 같습니다!
열거형의 케이스들을 배열처럼 순회할 수 있을까요?
네🙆🏻♀️ 할 수 있습니다. 열거형 정의시 CaseIterable 프로토콜을 상속받으면, 열거형의 케이스들로 이루어진 컬렉션을 만들어줍니다. 이렇게 하면 배열처럼 각 케이스 값들을 순회하며 함수를 반복적으로 실행 가능합니다.
enum Beverage: CaseIterable {
case coffee, tea, juice
}
allCases 프로퍼티로 컬렉션에 접근할 수 있습니다. 다른 컬렉션 타입처럼 .count 속성을 사용하면 컬렉션 내 요소의 개수도 셀 수 있습니다.
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
// Prints "3 beverages available"
for loop로 Beverage타입의 요소들을 순회하며 반복적으로 프린트 해 줄 수 있습니다,
for beverage in Beverage.allCases {
print(beverage)
}
// coffee
// tea
// juice
열거형의 각 케이스에는 원시값을 지정해줄 수 있습니다. 단, 모든 케이스의 원시값은 동일한 타입이어야합니다. (뒤에 나오는 연관 값과 크게 다른 점이지요) 각, 케이스의 원시값들은 unique해야합니다.(겹치면 안됩니다)
열거형을 정의할 때, 타입이름 오른쪽에 콜론과 함께 원시값의 타입을 명시해주면 됩니다.
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
Integer나 String타입으로 원시 값의 타입을 정의할 경우, 스위프트는 자동으로 원시 값을 지정해줍니다.
Integer타입의 경우엔, 첫 케이스 원시값은 '0'이며, 다음 케이스는 1만큼 씩 커집니다. 그리고 첫 케이스 값을 다른 정수값으로 지정해주어도, 그 다음 케이스가 1만큼 씩 증가하는 것은 동일합니다.
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
let earthOrder = Planet.earth.rawValue
// earthsOrder is 3
String타입은 case 이름 자체를 원시값으로 가집니다.
enum CompassPoint: String {
case north, south, east, west
}
let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"
Raw Value Initializer로 열거형 인스턴스를 만들 어 줄 수 있습니다. 인자로 원시값을 받고, 원시값과 매칭되는 케이스의 인스턴스를 반환 합니다. 존재하지 않는 케이스의 원시값이 들어올 경우 nil을 반환 할 수 있으므로, Raw Value Initializer는 옵셔널의 열거형 타입을 반환합니다.
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.uranus
스위프트에서는 각 케이스에 서로 다른 타입의 값들의 정보를 튜플로 저장할 수 있는 기능을 제공합니다. 동일한 타입의 정보만 저장해 주는 원시 값보다 더 유연한 정보를 저장할 수 있습니다.
사용방법을 알아볼까요?
열거형을 정의할 때 케이스 옆에 연관 값으로 저장하고 싶은 타입들을 튜플로 명시해주면 됩니다.
// 연관 값의 타입만 정의
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
// 실제 연관 값은 열거형 타입으로 새로운 인스턴스를 생성할 때 지정합니다.
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
따라서 동일한 케이스 일지라도 인스턴스마다 값이 다를 수 있습니다.
switch문과 결합해서 특정 연관 값을 추출해서 사용할 수도 있습니다. 각 연관 값을
'numberSystem'처럼 상수나 변수로 정의한 후, 해당 상수명이나 변수명을 통해 연관 값에 접근해줍니다.
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 "UPC: 8, 85909, 51226, 3"
Recursive Enumeration이란 하나 또는 하나 이상의 케이스가 같은 열거형 타입의 인스턴스를 연관 값으로 가지는 열거형을 의미합니다. 열거형 케이스가 재귀적이란 걸 알려주기위해 indirect키워드를 케이스 앞에 적어줍니다.
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}