[swift] enum, 열거형에 대하여

이은수, Lee EunSoo·2024년 8월 19일
0

Swift Basic

목록 보기
7/24
post-thumbnail

정의: 연관된 항목들을 묶어서 표현할 수 있는 타입

열거형은 다음과 같은 상황에서 사용하는것을 추천한다.

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

즉 카테고리처럼 정해진 종류의 값을 제공하고 처리하고 싶은때 사용하는 데이터 타입이라 할 수 있다.

사용방법

enum City {
	case Seoul
	case Busan
	case Incheon
	case Jeju
	case Changwon
}

enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

위와 같이 선언한다. 한줄로도 선언이 가능하다.

열거형의 타입지정

enum City {
	case Seoul
	case Busan
	case Incheon
	case Jeju
	case Changwon
}

열거형의 기본적인 사용방법

var myCity:City = City.Busan	// (1)
var myCity:City = .Busan 		// (2) 

선언시 타입을 지정해 준다면 City는 생략이 가능하다. (2번 코드)

switch에서의 사용

switch myCity{
case .Seoul
	print("myCity is Seoul")
case .Busan
	print("myCity is Busan")
case .Jeju
	print("myCity is Jeju")
case .Incheon
	print("myCity is Incheon")

}

myCity is Busan

열거형을 이용한 반복

enum Beverage: CaseIterable {
    case coffee, tea, juice
}

다음과 같이 음료를 정의하는 열거형을 선언한고 CaseIterable타입의 프로토콜을 지정해주면 반복문에서 사용이 가능하다

var range:Int = Beverage.allCases.count //열거형의 전체 길이 접근 가능

for beverage in Beverage.allCases{
	print(bevarage)
}

coffee
tea
juice

이런식으로 접근하면 자동으로 raw value 원시값을 생성해서 출력한다.

열거형의 원시값

열거형의 원시값 지정방법

enum City {
	case Seoul = "서울"
	case Busan = "부산"
	case Incheon = "인천"
	case Jeju = "제주"
	case Changwon = "창원"
}

위처럼 원시값을 할당하는게 안전하고 코드의 가독성을 높이는데 도움이 되지만 다음과 같이 암시적으로 값할당도 가능하다. 다음을 보자

암시적 할당(Implicitly Assigned Raw Values)

enum City: String {
	case Seoul 		// "Seoul"
	case Busan 		// "Busan"
	case Incheon 	// "Incheon"
	case Jeju 		// "Jeju"
	case Changwon 	// "Changwon"
}

사실 위처럼 직접 입력안해도 열거형이름 그래도 원시값을 쓰고 싶다면 열겨형의 타입을 명시해 주고 그대로 접근하면 이름 그대로 원시값이 적용된다.

이를 암시적인 원시값할당이라고 한다.

정수(Int)의 경우 열거형의 순서대로 정수값이 대입된다.

enum Numbers: Int{
	case One 		// 0
	case Two 		// 1
	case Three 		// 2
	case Four 		// 3
	case Ten = 10 	// 10 
} 

아래로 0부터 자동으로 채워서 저장해준다.
마지막 값이 10인 이유는 10으로 따로 지정해줘서 그럼, 아니면 그냥 4가 대입되었음(정수의 경우 그냥 순서대로 숫자를 대입한다.)

이처럼 타입을 지정하고 값을 입력해 주지 않아도 자동으로 원시값을 대입해준다.

연관 값

enum Human{
	case name(korName: String, engName: String)
    case age(Int)
    case address(String)

}

연관값에는 여러개의 데이터가 들어갈 수 있고, 헷갈리지 않게 이름을 지정 할 수 있다
(물론 생략하고 데이터 타입만 지정도 가능하다, 여러개일 경우에도 가능하다.)

var myInfo:Human = Human.name(korName: "은수", engName: "steve")

myInfo = .age(25) //앞서 Human타입으로 지정했으므로 Human은 생략이 가능하다.
myInfo = .address("경상남도 창원시 ...")

이렇게 지정이 가능하다.

연관값의 출력

var myInfo: Human = .name(korName: "은수", engName: "Steve")

switch myInfo{
case .name(let korName, let engName):
	print(korName, engName)
case .age(let age):
	print(age)
case .address(let address):
	print(address)
}

은수, steve

위와 같은 switch문을 이용하여 case 단위로 한개씩 접근해야 한다
(이때 데이터는 임시 지역변수로 감싸서 처리해야 한다.)

Q. 그렇다면 전체 연관값 출력은 어떻게 할까?

아쉽게도 열거형에는 연관값의 전체출력을 지원하는 키워드는 없다.

전체출력을 하려면 두가지 방법이 있다 다음 코드를 보자

방법1) 열거형 타입의 배열로


var myInfo: [Human] = [
    .name(korName: "은수", engName: "Steve"),
    .age(25),
    .address("경상남도 창원시 ...")
]

for info in myInfo {
    switch info {
    case .name(let korName, let engName):
        print("Korean Name: \(korName), English Name: \(engName)")
    case .age(let age):
        print("Age: \(age)")
    case .address(let address):
        print("Address: \(address)")
    }
}

Korean Name: 은수, English Name: Steve
Age: 25
Address: 경상남도 창원시 ...

방법2) fallthrough 키워드 사용

swift의 switch문은 fallthrough키워드가 있는데 간단하게 설명하면 switch문 안의 특정 case가 동작하면 자동으로 switch문이 종료되어야하는데 fallthrough를 사용하면 바로 다음 case를 검사하게된다. 바로 이 특성을 이용해서 출력한다.

switch myInfo {
    case .name(let korName, let engName):
        print("Korean Name: \(korName), English Name: \(engName)")
        fallthrough
    case .age(let age):
        print("Age: \(age)")
        fallthrough
    case .address(let address):
        print("Address: \(address)")
        fallthrough
    case .unknown:
        print("Unknown information")
    }

Korean Name: 은수, English Name: Steve
Age: 25
Address: 경상남도 창원시 ...

[tip] 열거형은 배열같은 컬렉션이 아니라서 전체출력을 하는데 사용하는것은 적절하지 못하다. 그래도 전체 출력을 자주 해야 하는 상황이 온다면 위 switch문을 함수로 만들어서 사용하자

재귀 열거형

이 글을 작성하고 있는 나조차도 조금 복잡하다 하지만 더 복잡한 방법이 있다 ㅎㅎ
바로 재귀 열거형 이다.

열거형에 indirection이라는 키워드를 사용하면 열거형 자기 자신을 연관값으로 지정 할 수 있다***

enum ArithmeticExpression {
    case number(Int)
    indirect case add(ArithmeticExpression, ArithmeticExpression)
    indirect case sub(ArithmeticExpression, ArithmeticExpression)
    indirect case mul(ArithmeticExpression, ArithmeticExpression)
    indirect case div(ArithmeticExpression, ArithmeticExpression)
}

열거형 선언부앞에 indirection키워드를 사용함으로 case에서 사용이 생략 가능하다

indirect enum ArithmeticExpression {
    case number(Int)
    case add(ArithmeticExpression, ArithmeticExpression)
    case sub(ArithmeticExpression, ArithmeticExpression)
    case mul(ArithmeticExpression, ArithmeticExpression)
    case div(ArithmeticExpression, ArithmeticExpression)
}

재귀 열거형 활용

//정수를 저장하는 열거형
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)

//정수를 저장한 열거형을 저장하는 열거형
let sum = ArithmeticExpression.add(five, four)
let product = ArithmeticExpression.mul(sum, ArithmeticExpression.number(2))

다음과 같이 사용이 가능하다.

func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .add(left, right):
        return evaluate(left) + evaluate(right)
    case let .sub(left, right):
        return evaluate(left) - evaluate(right)
    case let .mul(left, right):
        return evaluate(left) * evaluate(right)
    case let .div(left, right):
        return evaluate(left) / evaluate(right) + 
    }
}

사칙연산하는 함수를 열거형을 이용해 구현하였다.

profile
iOS 개발자 취준생, 천 리 길도 한 걸음부터

0개의 댓글