[Swift]- enum (1/3)

어흥·2023년 9월 21일

Swift

목록 보기
6/28

enum(열거형)

오늘은 enum 자료형에 대해서 알아보려고 한다.
열거형은 데이터 타입 중 하나로 관련된 값의 그룹을 위한 일반 타입을 정의하고 코드에서 타입-세이프 방법으로 값을 동작하게 한다.

  • Value type이다.

사용방법

CompassPoint에 저장된 열거형 값은 north, south, east, west이다.

enum CompassPoint {
    case north
    case south
    case east
    case west
}
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune

}
let compass1: CompassPoint = CompassPoint.north
let compass2: CompassPoint = .east
print(compass1)
print(compass2)

위를 실행하면
north
east
로 출력된다.

Raw Values

열거형의 case는 모두 독립적인 값이지만 내부에 또 다른 값을 저장할 수 있다. raw value를 이용하여 또 다른 값을 저장할 수 있다.
열거형 이름 뒤에 타입을 지정하여 case 마다 raw value를 할당할 수 있다. String, Charcter, Number Type 만 원시값의 타입으로 사용될 수 있다.

선언시점에 저장한 각 타입의 원시값은 나중에 바꿀 수 없으며 원시값을 저장하는 부분도 생략이 가능하다!
열거형을 각 타입으로 지정하여 사용해보자!

CompassPoint에 Int 타입으로 지정해보자!

enum CompassPoint: Int { // raw value를 지정하지 않는 것과 같다. 
    case north = 0
    case south
    case east
    case west
}
print(compass1.rawValue)
print(compass2.rawValue)

위 코드를 실행하면
0
2
가 출력된다.

enum CompassPoint: Int {
    case north 
    case south
    case east = 50
    case west
}
print(compass1.rawValue)
print(compass2.rawValue)

위 코드를 실행하면
0
50
가 출력된다.

Double형으로 지정한다면?!

enum CompassPoint: Double {
    case north = 0
    case south
    case east
    case west
}
print(compass1.rawValue)
print(compass2.rawValue)

위 코드를 실행하면
0.0
2.0
가 출력된다.

Double형으로 지정하고 raw value를 정수값으로 설정하지 않는다면 어떻게 될까?

enum CompassPoint: Double {
    case north = 1.1
    case south
    case east
    case west
}

print(compass1.rawValue)
print(compass2.rawValue)

오류가 발생한다.
이전의 raw value가 정수가 아닐 경우 enum case의 raw value를 정의해주어야한다. 위의 경우에도 east의 이전의 raw value인 1.1이 정수값이 아니므로 컴파일러가 east의 원시값을 어떤 값으로 정해야하는지 모른다는 것이다.

다음은 String 값으로 지정해보자!

enum CompassPoint: String {
    case north = "A"
    case south
    case east
    case west
}
print(compass1.rawValue)
print(compass2.rawValue)

A
east
가 출력된다.

열거형은 이름 그 자체만으로 의미를 가진다는 점에서 String으로 지정했을 때 별도의 raw value를 지정하지 않으면 이름이 출력되는 것이다.

지금까지 열거형의 원시값을 다양한 타입을 설정하여 사용해보았다. raw value로 정수가 사용되었다면 원시값이 설정되지 않은 일부 멤버에 대해서 자동 증가되는 것을 확인하였다. 이때 정수값을 할당해야만 1씩 증가 혹은 감소하게 된다!

열거형을 사용할 때, 원하는 raw value을 가지는 열거형을 변수에 할당할 수 있다.
String으로 타입이 지정된 바로 위 코드를 기준으로 코드를 작성해보겠다.

let someCompass = CompassPoint(rawValue: "B")

위 코드는 CompassPoint 열거형에서 raw Value로 "B"를 거지는 얘를 someCompass에 할당하는 것이다.
하지만 CompassPoint에서 rawValue로 "B"를 가지는 원소가 없다.

print(someCompass)

위 코드를 실행하면
nil
이 출력된다.
이처럼 nil을 리턴할 수 있기 때문에 생성자의 리턴형은 옵셔널(CompassPoint?)임을 알 수 있다.

raw value의 한계점은 다음과 같다.

raw value의 한계

  • 모든 케이스가 동일한 형식을 사용해야한다.
  • 케이스 당 저장할 수 있는 값이 단 한개이다.

이 한계를 해결하는 방법은 Associated Value를 사용하는 것이다.

Associated Values

사용 방법

enum Name {
    case caseName(Type)
    case caseName(Type, Type, ...)
}

Associated Values는 케이스 이름 뒤에 선언한다.(원시값의 형식은 열거형 이름 뒤에 선언)
새로운 열거형 인스턴스를 생성할 때 값을 저장한다. (원시값은 선언시점에 값 저장)
Tuple을 사용하여 하나의 케이스에 서로 다른 타입의 값을 저장할 수 있다. (named, unamed 모두 사용가능)

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

자신의 열거형 안에서 다른 타입으로 바꿀 수 있다. 아래와 같이 .upc에서 .qrCode로 변경이 가능하다!

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

0개의 댓글