정의: 연관된 항목들을 묶어서 표현할 수 있는 타입
열거형은 다음과 같은 상황에서 사용하는것을 추천한다.
즉 카테고리처럼 정해진 종류의 값을 제공하고 처리하고 싶은때 사용하는 데이터 타입이라 할 수 있다.
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 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 = "창원"
}
위처럼 원시값을 할당하는게 안전하고 코드의 가독성을 높이는데 도움이 되지만 다음과 같이 암시적으로 값할당도 가능하다. 다음을 보자
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 단위로 한개씩 접근해야 한다
(이때 데이터는 임시 지역변수로 감싸서 처리해야 한다.)
아쉽게도 열거형에는 연관값의 전체출력을 지원하는 키워드는 없다.
전체출력을 하려면 두가지 방법이 있다 다음 코드를 보자
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: 경상남도 창원시 ...
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) +
}
}
사칙연산하는 함수를 열거형을 이용해 구현하였다.