자바의 경우, 대부분의 열거 타입 상수는 자연스럽게 하나의 정숫값에 대응됩니다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal이라는 메서드를 제공합니다.
코드 35-1 ordinal을 잘못 사용한 예 - 따라하지 말것!
public enum Ensemble {
SOLO, DUET, TRIO, QUARTET, QUINTET,
SEXTET, SEPTET, OCTET, NONET, DECTET;
public int numberOfMusicians() { return ordinal() + 1; }
}
=> 동작은 하지만 유지보수하기가 끔찍한 코드입니다. 상수 선언 순서를 바꾸는 순간 numberOfMusicians
가 오동작하며 이미 사용중인 정수와 값이 같은 상수는 추가할 방법이 없습니다. 또한 값을 중간에 비워둘 수도 없습니다.
해결책은 간단합니다. 열거 타입 상수에 연결된 값은 ordinal 메서드로 얻지 말고, 인스턴스 필드에 저장하면 됩니다.
public enum Ensemble {
SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
SEXTET(6), SEPTET(7), OCTET(8), DOUBlE_QUARTET(8),
NONET(9), DECTET(10), TRIPLE_QUARTET(12);
private final int numberOfMusicians;
Ensemble(int size) { this.numberOfMusicians = size; }
public int numberOfMusicians() { return numberOfMusicians; }
}
EnumSet, EnumMap 의 key로 사용하는 경우입니다. 이런 성격의 목적에만 ordinal()를 사용하도록 합니다.
import java.util.*;
enum days {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
public class EnumSetExample {
public static void main(String[] args) {
Set<days> set = EnumSet.of(days.TUESDAY, days.WEDNESDAY);
// Traversing elements
Iterator<days> iter = set.iterator();
while (iter.hasNext())
System.out.println(iter.next());
}
}
enum Ensemble: Int {
case solo
case duet
case trio
case quartet
case quintet
case sextet
case septet
case octet
case nonet
case dectet
var numberOfMuscians: Int {
return rawValue + 1
}
}
=> 자바의 ordinal()과 마찬가지로, 동작은 하지만 유지보수하기가 끔찍한 코드입니다. 상수 선언 순서를 바꾸는 순간 numberOfMusicians
가 오동작하며 이미 사용중인 정수와 값이 같은 상수는 추가할 방법이 없습니다. 또한 값을 중간에 비워둘 수도 없습니다.
rawValue에 명시적으로 값 대입하여 사용하기
enum Ensemble: Int, CaseIterable {
case solo = 1
case duet = 2
case trio = 3
case quartet = 4
case quintet = 5
case sextet = 6
case septet = 7
case octet = 8
case doubleQuartet = 8 // 컴파일 에러! => Raw value for enum case is not unique
case nonet = 9
case dectet = 10
case tripleQuartet = 12
var numberOfMusicians: Int {
return rawValue
}
}
enum Ensemble: Int {
case solo, duet, trio, quartet, quintet, sextet, septet, octet, doubleQuartet, nonet, dectet, tripleQuartet
var numberOfMuscians: Int {
switch self {
case .solo:
return 1
case .duet:
return 2
case .trio:
return 3
case .quartet:
return 4
case .quintet:
return 5
case .sextet:
return 6
case .septet:
return 7
case .octet:
return 8
case .doubleQuartet:
return 8
case .nonet:
return 9
case .dectet:
return 10
case .tripleQuartet:
return 12
}
}
}
=> 하지만 이 방식은 연산 프로퍼티가 하나씩 추가될 때마다 위처럼 계속 나열해야하는 단점이 있습니다.
또 다른 방법으로는 구조체(struct)와 열거 타입(enum)을 혼합해서 사용하는 방법이 있습니다.
Ensemble
)로 선언합니다. 따라서 저장 프로퍼티를 가질 수 있으므로, numberOfMusians를 프로퍼티로 갖게 할 수 있습니다.Kind
)을 갖게 합니다. 위의 예시와 똑같이 Ensemble의 모든 case를 갖게 할 수 있습니다.static let
)로서 선언할 수 밖에 없습니다.struct Ensemble {
enum Kind {
case solo, duet, trio, quartet, quintet, sextet, septet, octet, doubleQuartet, nonet, dectet, tripleQuartet
}
let kind: Kind
let numberOfMusicians: Int
private init(kind: Kind, numberOfMusicians: Int) {
self.kind = kind
self.numberOfMusicians = numberOfMusicians
}
static let solo = Ensemble(kind: .solo, numberOfMusicians: 1)
static let duet = Ensemble(kind: .duet, numberOfMusicians: 2)
static let trio = Ensemble(kind: .trio, numberOfMusicians: 3)
static let quartet = Ensemble(kind: .quartet, numberOfMusicians: 4)
//... 생략
}
var ensemble: Ensemble = .solo
print(ensemble.numberOfMusicians) // 1
ensemble = .octet
print(ensemble.numberOfMusicians) // 8
ensemble = .doubleQuartet
print(ensemble.numberOfMusicians) // 8
// numberOfMusicians의 값으로 중복이 가능합니다.
=> Kind
는 예시로 든 이름일 뿐이지, 꼭 따르지 않아도 됩니다. struct 이름으로 Choir
, 중첩 enum 이름으로 Ensemble
도 어울립니다.
Kind
)를 사용하면 일반 열거형처럼 분기처리할 수 있습니다.// 외부에서 사용하는 경우
func foo(ensemble: Ensemble) {
switch ensemble.kind {
case .solo:
break
case .duet:
break
case .trio:
break
//... 생략
}
enum MyType {
Type1, // 0
Type2, // 1
Type3, // 2
NumberOfTypes // 3 == all count
}
=> 마지막 NumberOfTypes
가 3이 되어 저절로 모든 case의 총 개수로 이용될 수 있습니다. 하지만 이 방법은 NumberOfTypes
가 무엇을 뜻하는지 팀원들끼리 공유해야 하고, 이후 코드를 잘못 건드릴 경우 총 개수로서 작동하지 않을 수 있는 위험이 있습니다.
enum MyType: CaseIterable {
case type1
case type2
case type3
static var count: Int {
return allCases.count
}
}
https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html