GGURUPiOS

Swift 공식 문서 정리 - (8) Enumerations 본문

Swift/공식문서 정리 ( 문법 )

Swift 공식 문서 정리 - (8) Enumerations

꾸럽 2023. 4. 27. 20:25

Enumerations ( 열거형 )

열거형은 관련된 값으로 이루어진 그룹의 공통의 형임
타입 세이프티를 보장하는 방법으로 다룰 수 있게 해줌
열거형은 1급 객체형 이어서 계산된 프로퍼티를 제공하고 초기화를 지정하거나 초기 선언을 확장해 사용할 수 있음

열거형 문법

enum SomeEnumeration { // enumeration definition goes here }

일반적으로 위와 같이 작성한다

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

/* 공식문서에서 
열거형은 다른언와 달리 기본적으로 정수 값이 할당되지 않는다.
north,south,east,west는 0,1,2,3 이라는 값을 가지지 않으며,
각 case는 그냥 고유한 값임
*/

여러 case 를 콤마로 구분해서 한줄에 적을 수 있음

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

각 열거형 정의는 완전 새로운 타입을 정의하는 것이기 때문에 타입의 이름은 대문자로 시작해야함 (위의 Planet처럼)

Switch 구문에서 열거형 값 매칭하기

각 열거형 값을 Switch 문에서 매칭할 수 있음

var directionToHead = CompassPoint.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문은 철저해야하기 때문에, 열거형의 모든 케이스가 있어야 한다.

열거 사례 반복

일부 열거형의 경우 해당 열거형의 모든 사례 모음을 보유하는 것이 유용함.

열거형 이름뒤에 CaseIterable을 작성하면 allCases라는 프로퍼티를 노출한다.(접근 가능)

enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\\(numberOfChoices) beverages available")
// Prints "3 beverages available"

또한 다른 컬렉션들 처럼 for-in 문을 돌릴 수 있음.

for beverage in Beverage.allCases {
    print(beverage)
}

관련 값 (관계 값? associated value)

열거형의 각 case에 추가적인 정보를 저장할 수 있음

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

// 4가지 구분으로 된 바코드와, 2953개의 문자로 구성된 
// QR코드 바코드 두종류가 있다면 위와같이 열거형을 구성할 수 있음

// 새 바코드 생성
var productBarcode = Barcode.upc(8, 85909, 51226, 3)

// 동일한 제품에 다른 유형 할당 가능 
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

관련 값은 switch 문에서 상수 혹은 변수로 선언해서 접근 할 수 있음

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

// 공통된 'let' 을 빼서 앞으로 꺼낸 모습

Raw 값

연관된 값에 대한 대안으로 열거형 케이스는 동일한 타입인 기본값으로 미리 채워질 수 있음

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

위의 예제는 Character로 raw값을 정의했지만 String, Character, Integer, Float등 타입도 가능함.
단, raw값은 중복되어서는 안됨
Raw값은 관련값과는 다름. Raw값은 코드에서 열거형을 처음 선언할때 정의 됨. 특정 열거형의 raw값은 항상 같은 값을 가짐
하지만 관계값은 같은 case라도 생성될때 달라짐.

암시적으로 할당된 Raw값

만약 raw값을 할당하지 않으면, Swift에서 자동으로 값을 할당해줌

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

// mercury 에 1일 명시적 할당하면, venus는 2, earth는 3 ...
// 이런식으로 자동으로 갖게 됨 

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

// String을 raw값으로 사용하면 case 텍스트가 자동으로 raw 값이 됨
// raw값은 rawValue프로퍼티를 사용해 접근 가능 

Raw 값을 이용한 초기화

raw값을 이용해 열거형 변수를 초기화 가능함.

아래 예제는 raw값 7을 갖는 값을 열거형 변수의 초기값으로 지정

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

/* 공식문서에서 
raw 값을 이용한 초기화는 모든 raw값에 대해 반환이 보장되지 않으므로(실패할 수 있으므로
failable initializer임. -> nil 값이 올 수 도 있다는 뜻. 
*/

아래 예제에서는 rawValue가 11인 case 가 없기 때문에 실패함

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"

재귀 열거형

재귀 열거형은 다른 열거 인스턴스를 관계 값으로 갖는 열거형임 재귀 열거자 case 는 앞에 indirect 키워드를 붙여 표시

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

모든 열거형 case 에 indircet를 표시하고 싶으면 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))

// product가 실제로 연산을 수행하는 것은 아니고, ( 5 + 4 ) * 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))
// 18 출력