Swift

Swift Collection - 열거형

호종이 2022. 2. 13. 20:22

열거형은 연관된 항목들을 묶어서 표현할 수 있는 타입으로, 프로그래머가 정의해준 값 외에는 추가나 수정이 불가능하다. 그렇기 때문에 딱 정해진 값만 열거형 값에 속할 수 있다. 

열거형은 다음과 같은 상황에 유용하게 사용할 수 있다. 

  • 제한된 선택지를 주고 싶을 때
  • 정해진 값 외에는 입력받고 싶지 않을 때
  • 예상된 입력 값이 한정되 있을 때

즉 연관된 값들을 높은 가독성으로 나열하는데 특화되있으며, 실생활에서 이미 열거형으로 사용할 수 있는 개념들이 많다. 예를 들어 요일은  [월요일,화요일,수요일,목요일,금요일,토요일,일요일] 으로만 이루어져 있기 때문에, 이것을 열거형으로 만들면 해당 API 를 사용하는 프로그래머는 무조건 정의된 요일만 사용할 수 있다.

 

기본 열거형


스위프트의 기본 열거형은 enum 이라는 키워드로 선언할 수 있으며, 각 열거형은 이름을 가질 수 있다.

enum Day {
    ...
}

그리고 열거형의 각 데이터는 case 키워드로 선언할 수 있으며, 한 줄에 모두 표현할 수 있다.

enum Day {
    case Monday
    case Tuesday
    case Wednesday
    case Thursday
    case Friday
    case Saturday
    case Sunday
}

//or

enum Day {
    case Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
}

스위프트의 열거형은 다음과 같이 사용할 수 있다.

var currentDay : Day = Day.Monday 
var tomorrow = Day.Tuesday //타입 추론
var yesterday :Day = .Sunday //열거형의 타입을 정해줌

원시 값


열거형의 각 항목은 원시 값을 가질 수 있다. 특정 원시 값을 가지고 싶다면 열거형 이름 타입 오른쪽에 다음과 같이 타입을 명시해주면 된다.

enum Day : Int {
    case Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
}

or

enum Day : Int {
    case Monday = 0,Tuesday = 1,Wednesday = 2,Thursday = 3,Friday = 4,Saturday = 5,Sunday = 6
}

raw Value 의 타입을 저렇게 할당해줄 수 있으며, 아래와 같이 열거형.rawValue 라는 프로퍼티를 사용해 값을 가져올 수도 있다.

enum Day : Int {
    case Monday = 0,Tuesday = 1,Wednesday = 2,Thursday = 3,Friday = 4,Saturday = 5,Sunday = 6
}

print(Day.Monday.rawValue)
//출력 결과
0

원시 타입을 지정해줬다고 해서, 모든 열거형에 값을 지정할 필요가 없다. 값을 지정하지 않아도 컴파일러가 알아서 처리해주며, 문자열을 원시 타입으로 지정해주면 각 항목의 이름을, 정수를 지정해주면 0 부터 순서대로 1씩 늘어난 값을 원시형으로 갖게 된다. 

즉 위 코드에서 열거형에 값을 할당해주지 않더라도 Monday 의 rawValue 는 0이 된다는 소리다

또한 rawValue 를 가지고 열거형을 얻을 수 있다. Monday 의 rawValue 는 0이기 때문에, 0으로 Monday 를 가져올 수 있다.

enum Day : Int {
    case Monday = 0,Tuesday = 1,Wednesday = 2,Thursday = 3,Friday = 4,Saturday = 5,Sunday = 6
}

var currentDay = Day(rawValue: 0)
var what = Day(rawValue: 10) //만약 10인 rawValue 를 가지는 열거형이 없으면, nil 이 된다!

 

연관 값


열거형은 관련된 연관값을 가질 수 있다. 각 열거형마다 관련된 값을 소괄호로 묶어 표시할 수 있으며, 다른 항목이 연관값을 가진다고 해서 무조건 모든 항목이 가질 필요는 없다. 

 

음식점을 예로 들어보자. 음식점은 피자를 전문으로 팔며, 하와이안 피자, 오리지널 피자, 불고기 피자를 판매한다. 또 각 피자를 주문할 때 갈릭 소스, 핫소스, 달콤소스를 선택할 수 있다. 

 

우리는 위 정보를 가지고 두 가지의 열거형을 만들 수 있다. 

enum Pizza {
    case HawaianPizza
    case OriginalPizza
    case BulgogiPizza
}

enum Sauce{
    case Garlic
    case Hot
    case Sweet
}

각 피자를 주문할 때 손님이 소스를 선택할 수 있기 때문에, 소스를 피자의 연관값으로 추가시켜보자!

enum Pizza {
    case HawaianPizza(sauce:Sauce)
    case OriginalPizza(sauce:Sauce)
    case BulgogiPizza(sauce:Sauce)
}

enum Sauce{
    case Garlic
    case Hot
    case Sweet
}

이제 우리가 Pizza 타입의 변수를 생성할 때 다음과 같이 생성할 수 있다.

let MyPizza : Pizza = .OriginalPizza(sauce: .Hot)
let disgustingPizza = Pizza.HawaianPizza(sauce: .Garlic)

Switch 와 함께 사용하기


Swift 의 열거형은 switch 문과 함께 사용하면 더욱 강력해진다. 내가 주문한 피자가 뭔지 알고 싶다면, 다음 코드를 살펴보자

let MyPizza : Pizza = .OriginalPizza(sauce: .Hot)
let disgustingPizza = Pizza.HawaianPizza(sauce: .Garlic)

switch MyPizza {
    case .HawaianPizza(sauce: _):
        print("내가 선택한 피자는 하와이안 피자입니다. 소스는 아무거나 상관없습니다. 정말 싫은 피자네요")
    case .OriginalPizza(sauce: let sauce):
        print("내가 선택한 피자는 오리지널 피자로, 소스는 \(sauce)입니다")
    case .BulgogiPizza(.Garlic):
        print("내가 선택한 피자는 불고기 피자로, 소스는 무조건 갈릭 소스여야 합니다.")
    default:
        print("몰라")
}

우선 switch 문의 첫 번째 케이스를 보자. 우리가 Pizza 열거형에 소스라는 연관값을 추가했으므로, 이 열거형을 switch 문으로 판별할 때 소스에 대한 정보도 필요하다. 이 때 아무 소스를 가진 하와이안 피자를 해당 케이스로 진입하게 하고 싶다면, 연관값에 _ 를 사용해서 연관값을 무시할 수 있다.

두 번째 케이스는 OriginalPizza 일 때 진입할 수 있으며, 소스에 대한 정보를 내가 접근해야 할 때 사용할 수 있다. let 을 통해 실제 소스 값과 바인딩 시켜줄 수 있으며, sauce 상수를 사용해 데이터에 접근할 수 있다.

세 번째 케이스는 오로지 갈릭 소스만 가진 불고기 피자로만 접근할 수 있다. 

 

if 문과 함께 사용하기


if case Pizza.HawaianPizza(sauce: let sauce) = MyPizza {
    print(sauce)
}
if case Pizza.HawaianPizza(sauce: _) = MyPizza {
    print("하와이안 피자입니다.")
}

if case Pizza.OriginalPizza(sauce: Sauce.Hot) = MyPizza {
    print("내가 선택한 피자는 오리지널 핫소스 피자입니다.")
}

if문과도 마찬가지로 사용할 수 있으며, 위와 같이 연관값을 바인딩하거나, 무시하거나, 지정해서 받을 수 있다.