[Swift] Enum (2/3)

어흥·2024년 5월 8일

Swift

목록 보기
7/28

안녕하세요! enum 2편으로 돌아왔습니다. 너무 오랜만에 2편으로 돌아온 관계로 복습부터 빠르게 시작해보겠습니다!

열거형은 데이터 주제에 따라 몇가지로 한정된 값만을 가지는 경우 사용하는 자료형입니다. 간편하게 상수 데이터의 집합이라고 말할 수도 있겠네요.

예를 들어 요일 혹은 방향 데이터를 취급해야할 때, 요일은 월, 화, 수, 목, 금, 토, 일로 이루어져 있고 방향은 동, 서, 남, 북과 같이 한정된 요소로 이루어져 있어 열거형을 사용하기 적합합니다.

열거형은 기존 case에 값을 부여해서 사용할 수도 있고 추가 데이터를 넣어서 사용할 수도 있는데요. 이를 원시값과 연관값이라고 합니다. 간단히 살펴보겠습니다!

원시값(raw value)

원시값은 열거형의 각 케이스에 부여된 정수 또는 문자열 값으로, 원시값을 사용하면 열거형의 케이스에 더 쉽게 생성하거나 접근할 수 있다는 점에서 편리합니다.

  • 열거형의 선언시점에서 값을 저장
  • 값 변경 불가능
  • 선언 타입 제한 - Hashable한 타입만 사용 가능( 주로 Int, String 사용)
enum RpsGame: Int {
    case rock
    case paper
    case scissors
}
enum Alignment1: String {
    case left = "L"
    case center = "C"
    case right = "R"
}
RpsGame(rawValue: 0) // .rock 

연관값(associated value)

연관값은 열거형 타입의 각 케이스에 추가적으로 저장되는 데이터로 보다 하나의 케이스 안에서 상이한 특징을 가지고 있는 주제일 때 활용하면 좋습니다.

  • 하나의 케이스에 서로 다른 연관값을 저장 가능
  • 선언 타입에 상관없이 자유롭게 정의 가능
  • 인스턴스 생성시 값 저장
  • 값 변경 가능하고 같은 케이스에 서로 다른 값 저장 가능
enum Computer {
    case cpu(core: Int, ghz: Double)
    case ram(Int, String)
    case hardDisk(gb: Int)
}
let myChip1 = Computer.cpu(core: 8, ghz: 3.5)
let myChip2 = Computer.cpu(core: 4, ghz: 2.0)

let myChip3 = Computer.ram(16, "DRAM")
let myChip4 = Computer.ram(4, "SRAM")

주의할 점

주의할 점은 하나의 열거형에서 원시값과 연관값을 동시에 사용하는 것은 불가능하다는 것!! 입니다.


그럼 본격적으로 열거형이 어떻게 활용될 수 있는지 알아보겠습니다!

열거형 with Switch 문

앞에서 말했다시피 열거형은 한정된 사례(case)로 만든 타입입니다. 그리고 switch 문은 표현식에 대한 분기처리를 수행할 때 사용하기 적합합니다.

따라서 switch문과 열거형을 함께 자주 사용합니다.

enum LoginProvider: String {      // 3가지로 정의
    case email
    case facebook
    case google
}

let userLogin = LoginProvider.facebook

switch userLogin {              
case .email:
    print("이메일 로그인")
case .facebook:
    print("페이스북 로그인")
case .google:
    print("구글 로그인")
}

위 코드처럼 switch문을 활용하면 열거형의 각 케이스에 맞게 처리하는 것을 확인할 수 있습니다.

옵셔널 열거형

우리는 optional 편에서 optional이 내부적으로 열거형으로 구현되었다는 것을 배웠습니다. 그렇다면 옵셔널 열거형일 때, switch문을 통해서 값에 어떻게 접근할지 알아보겠습니다!

enum OpEnum {
    case left
    case right
}
let x: OpEnum? = .left

위 코드를 보면 상수 x가 optional 열거형으로 선언된 것을 확인할 수 있습니다. 그러면 switch문을 활용하여 옵셔널 열거형을 어떻게 분기처리할 수 있을까요?

optional 열거형은 하나의 열거형에 다른 열거형에 포함된 상태라고 생각하면 쉽게 떠올릴 수 있습니다.

optional은 2가지 케이스로 구성된 열거형입니다.

  • some 케이스 -> OpEnum (case: .left, case: right)
  • none 케이스

이러면 2가지 switch문을 활용하여 분기처리를 할 수 있겠죠?

switch x {
case .some(let value):      // Optional.some(let value) = Optional.some(SomeEnum.left)  ⭐️
    switch value {
    case .left:
        print("왼쪽으로 돌기")
    case .right:
        print("오른쪽으로 돌기")
    }
case .none:
    print("계속 전진")
}

optional 처리를 위해, some, none 케이스로 나눠 처리하고 some일 경우 left, right 케이스 분기처리를 수행하는 것입니다.

이보다 더 간편한 방법이 있습니다. 스위프트에서 옵셔널 열거형을 더 편리하게 처리하는 방법을 제공하고 있습니다. (옵셔널 처리를 위한 some, none 케이스 분기처리 생략 가능)

switch x {  
case .left:
    print("왼쪽으로 돌기")
case .right:
    print("오른쪽으로 돌기")
case nil:
    print("계속 전진")
}

연관값이 있는 케이스 처리

바인딩을 활용하여 효과적으로 연관값을 가지는 열거형 케이스를 처리할 수 있습니다.

switch 문을 활용하여 모든 케이스 처리

열거형 선언 부분 위 코드 참조

switch chip {
case .cpu(core: 8): // core 8을 가지는 cpu 처리
	print(CPU-8코어”)
case .cpu(core: let c): // 바인딩을 활용하여 모든 cpu 케이스 처리
	print(CPU-\(c))
case .ram(_): // 모든 ram 처리
	print(RAM)
case let .hardDisk(gb: g): // 바인딩을 활용하여 모든 hardDisk 처리
	print(“하드-\(g)기가”)
}

if문 활용하여 특정 케이스 처리

var chip = Computer.hardDisk(gb: 128)

if case .hardDisk(gb: let a) = chip {
    print("이 칩은 \(a)gb 하드디스크입니다. ")
}

if case .hardDisk(gb: let a ) = chip, a == 128 { // 조건 추가
	print("이 칩은 128gb 하드디스크입니다. ")
}

for문 활용하여 특정 케이스 처리

let chiplists: [Computer] = [
    .cpu(core: 4, ghz: 3.0),
    .cpu(core: 8, ghz: 3.5),
    .ram(16, "SRAM"),
    .ram(32, "DRAM"),
    .cpu(core: 8, ghz: 3.5),
    .hardDisk(gb: 500),
    .hardDisk(gb: 256)
]
for case let .cpu(core: a, ghz: b) in chiplists {
	print("cpu: \(a) core, \(b) 헤르츠")
}

0개의 댓글