[Swift5] Enumerations 2

Junyoung Park·2022년 3월 7일
0

Swift5 Docs

목록 보기
18/37
post-thumbnail
  • 다음은 Swift 5.6 Doc의 Enumerations 공부 내용을 정리했음을 밝힙니다.

Enumerations

연관값

연관값(associated values)을 통해 다른 타입 값을 열거 케이스에 지정할 수 있다.

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

바코드 열거 타입은 upc로 연관된 정수 타입을 인식하거나 qrCode로 정수를 받아들인다. 연관값이 실제 이러한 타입 데이터를 제공하는 게 아니라, 열거 타입으로 들어오는 변수나 상수의 데이터 타입을 정의한다는 데 주의하자. productBarcode 변수의 경우 upc로는 정수 네 개, qrCode로는 문자열을 받아들인다.

스위치 문으로도 열거 타입 내 정의된 다른 케이스와 매칭할 수 있다.

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

열거 케이스 종류가 각자 다르다면, 즉 변수와 상수가 다르다면 따로 선언해야 하지만 모두 같은 종류일 때에는 case 뒤에 var 또는 let으로 한꺼번에 선언할 수도 있다.

원시값

원시값(raow values)는 연관값을 사용자가 정의하기 전에 디폴트로 제공되며, 모두 같은 타입이다.

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

위 열거 케이스에서 각 케이스들이 캐릭터 타입으로 정의되어 있는데, 이외에도 스위프트가 지원하는 기본적인 데이터 타입을 모두 사용 가능한데, 원시값은 열거 타입을 정의할 때 다른 값과 중복되지 않아야 한다.

원시값 할당 생략

원시값을 할당할 때 케이스마다 원시값을 할당하지 않아도 스위프트가 자동으로 할당해준다.

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

let earthsOrder = Planet.earth.rawValue
// earthsOrder is 3

Planet 케이스를 시작하는 mercury가 정수 1로 할당받았기 때문에, 이후 값 할당이 생략된 다른 케이스는 자동으로 원시값 2, 3... 등이 할당된다.

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

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"

Planet처럼 특정 값이 할당되지 않은 문자열 타입일 때에는 그 이름 자체가 원시값이 된다.

원시값 이니셜라이저

원시값으로 열거 타입을 사용할 때, 열거 타입을 사용할 때 원시값 타입 데이터를 받는 초기화 선언을 자동으로 받고 열거 케이스나 nil을 리턴한다.

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

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"

이 경우 positionToFind = 11Planet 열거 타입에 정의되지 않았기 때문에 옵셔널이 nil로 리턴되고, 옵셔널 바인딩에 의해 타입 세이프하게 else 구문이 실행된다.

열거 재귀 사용

열거 타입이 다른 열거 타입 인스턴스를 가질 수도 있다. 이때 열거를 재귀적으로 사용했다고 알려줄 수 있다.

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

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"

열거 케이스가 열거 타입 인스턴스인 경우에만 indirect를 붙일 수도 있고, 아예 enum 앞에 indirect를 붙여도 된다. 이때 addition이나 multiplicationArithmeticExpression에 정의된 ArithmeticExpression.number라는 케이스를 받아들이는데, evaluate라는 ArithmeticExpression을 파라미터로, 정수를 리턴하는 함수를 통해 연산을 지원한다.

profile
JUST DO IT

0개의 댓글