enum은 한정된 값의 집합을 표현하는 타입이다.
예를 들어, 동물의 종류처럼 "정해진 선택지"를 다룰 때 쓰기 좋다.
enum Animals {
case cat
case dog
case rabbit
}
이렇게 Animals.cat처럼 쓰면, 이것 자체가 enum 타입의 값이 된다.
출력하면 "cat"처럼 보일 수도 있지만, 실제로는 문자열이 아니다.
문자열처럼 출력하고 싶으면 어떻게 하지?
그럴 땐 RawRepresentable을 활용하면 된다.
뒤에 붙는거는 프로토콜인데 이건 스웨덴 형님이 나중에 알려주신다고 참고만 하시란다.
(지금은 클로저 후유증이 좀 남아있으니 더 안파고 넘어가보겠다.)
enum Animals: String {
case cat, dog, rabbit
}
print(Animals.cat.rawValue) // "cat"
정해진 상태나 선택지를 표현하고 싶을 때 enum이 제격이다.
예를 들어:
.loggedIn, .loggedOut.loading, .success(data), .failure(error).left, .right왜 좋냐면
switch문과 찰떡이고, 연관 값을 붙여서 다양한 상태를 안전하게 표현할 수 있기 때문이다.
== 비교가 안 되는 이유는?enum Shortcut {
case fileOrFolder(path: URL, name: String)
case wwwUrl(path: URL)
}
let a = Shortcut.wwwUrl(path: URL(string: "https://apple.com")!)
if a == Shortcut.wwwUrl(path: URL(string: "https://apple.com")!) {
// Error 발생
}
왜 안 될까?
바로, 연관 값이 있는 enum은 자동으로 Equatable을 채택하지 않기 때문이다.
enum Shortcut: Equatable {
case fileOrFolder(path: URL, name: String)
case wwwUrl(path: URL)
}
switch는 왜 잘 작동할까?switch a {
case .wwwUrl(let path):
print(path)
default:
break
}
switch는 패턴 매칭 기반이라, Equatable이 없어도 내부 case 구조를 직접 분해해서 비교한다.
즉, == 연산이 아니라 구조 자체를 비교하는 방식이다.
==는 값을 비교하는거라고 한다면 switch같은 경우에는, 값이 특정 구조, 모양, 조건을 만족하는지 검사하는 방식
if case let .wwwUrl(path) = a {
print(path)
}
// 이거랑 똑같다고 보면 된다
switch a {
case let .wwwUrl(path):
print(path)
break
defualt:
"somthing else..."
}
이건 switch를 줄여 쓴 문법이다.
특정 케이스만 확인하고, 연관 값도 꺼내고 싶을 때 아주 편리하다.
비슷하게 guard case, for case, while case도 쓸 수 있다.
indirect?이게 조금 난이도 있는 부분이다.
indirect enum IntOperation {
case add(Int, Int)
case subtract(Int, Int)
case freeHand(IntOperation)
}
여기서 freeHand는 다시 IntOperation을 포함하고 있다.
이건 재귀 구조인데, Swift의 enum은 값 타입이라 스스로를 가질 수 없다.
그래서 indirect 키워드를 써서 힙에 저장되도록 한다.
indirect enum IntOperation {
case add(Int, Int)
case subtract(Int, Int)
case freeHand(IntOperation)
func calculateResult(
of operation: IntOperation? = nil
) -> Int {
switch operation ?? self {
case let .add(lhs, rhs):
return lhs + rhs
case let .subtract(lhs, rhs):
return lhs + rhs
case let .freeHand(operation):
return calculateResult(of: operation)
}
}
}
여기서 핵심은 operation ?? self다.
함수 호출 시 매개변수가 없으면 self를 쓰는 구조다.
즉, 이런 식으로도 가능하다:
let freeHand = IntOperation.freeHand(.add(20, 30))
freeHand.calculateResult() // 50
| 항목 | struct | enum |
|---|---|---|
| 목적 | 여러 속성을 가진 데이터 구조 표현 | 상태나 선택지를 표현 |
| 구성 | 여러 프로퍼티 가능 | 한 번에 하나의 case만 존재 |
| 연관값 | 없음 (모든 속성이 고정 필드로 존재) | 특정 case에만 연관값 가능 |
| switch 사용 | ❌ | (switch, if case 등 패턴 매칭 가능) |
| 상속 | ❌ | ❌ |
enum은 상태를 표현하고,
struct는 데이터를 담는다.