열거형은 특수한 클래스로, 개수가 고정된 상수 집합을 표현할 때 사용합니다.
모든 열거형은 자동으로 Enum 클래스를 상속받습니다. 또한 열거형은 봉인 타입(sealed)이므로 상속하거나 구현, 믹스인할 수 없고 명시적으로 직접 인스턴스를 생성할 수도 없습니다.
추상 클래스와 믹스인(mixin)은 명시적으로 Enum을 구현하거나 상속할 수 있지만, 열거 선언에서 구현 또는 믹스인하지 않으면 해당 클래스나 믹스인의 실제 객체를 만들 수 없습니다.
enum 키워드를 사용하고 열거 상수를 나열하면 간단한 열거형을 정의할 수 있습니다.
enum Color { red, green, blue }
열거형 선언 끝에 쉼표를 추가할 수 있어 복사 붙여넣기 시 코드 오류를 줄이기 유리합니다.
확장 열거형(Enhanced enums)
Dart는 확장 열거형을 지원하며 일반 클래스처럼 멤버 필드, 메서드, 상수 생성자를 정의할 수 있습니다. 단 인스턴스는 미리 정의된 고정 상수만 존재할 수 있습니다.
확장 열거형을 선언할 때는 강제로 지켜야 하는 규칙이 여러 가지 있습니다.
- 인스턴스 변수는 반드시
final로 선언해야 합니다(믹스인을 통해 가져온 변수 포함) - 모든 생성자는
const키워드를 붙여야 합니다 - 팩토리 생성자는 열거형 내부에 미리 정의된 상수 인스턴스만 반환 가능
- 다른 클래스를 명시적으로 상속할 수 없습니다(
Enum을 자동 상속) index,hashCode, 동등 연산자==를재정의할 수 없습니다- 열거형 안에
values라는 이름의 멤버를 정의하면 안 됩니다. 자동 생성되는 정적values접근자와 충돌합니다 - 모든 열거 인스턴스는 열거 정의 맨 앞에 작성해야 하고 최소 한 개 이상의 인스턴스가 존재해야 합니다
- 확장 열거형의 인스턴스 메서드 안에서
this로 현재 열거 상수를 가리킬 수 있습니다
예시
enum Vehicle implements Comparable<Vehicle> {
car(tires: 4, passengers: 5, carbonPerKilometer: 400),
bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);
const Vehicle({
required this.tires,
required this.passengers,
required this.carbonPerKilometer,
});
final int tires;
final int passengers;
final int carbonPerKilometer;
// Getter
int get carbonFootprint => (carbonPerKilometer / passengers).round();
bool get isTwoWheeled => this == Vehicle.bicycle;
@Override
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}Code language: Dart (dart)
Dart 3.13 이상 버전에서는주 생성자를 지원해 확장 열거형 구문을 간소화할 수 있습니다.
enum Vehicle(
final int tires,
final int passengers,
final int carbonPerKilometer,
) implements Comparable<Vehicle> {
car(4, 5, 400),
bus(6, 50, 800),
bicycle(2, 1, 0);
int get carbonFootprint => (carbonPerKilometer / passengers).round();
bool get isTwoWheeled => this == Vehicle.bicycle;
@Override
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}Code language: Dart (dart)
열거형 사용하기
열거 상수에 접근하는 방식은 정적 변수에 접근하는 방식과 동일합니다.
final favoriteColor = Color.blue;
if (favoriteColor == Color.blue) {
print('Your favorite color is blue!');
}Code language: Dart (dart)
index 속성
모든 열거 상수에는 index 속성이 존재하며, 정의 순서 기준0부터 시작하는 순번을 반환합니다.
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);Code language: Dart (dart)
values 정적 상수
열거이름.values로 모든 열거 값을 담은 리스트를 얻을 수 있습니다.
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);Code language: Dart (dart)
switch와 열거형 함께 사용
switch에서 열거형을 사용할 때 모든 열거 케이스를 처리하지 않으면 컴파일러가 경고를 표시합니다. default로 예외 케이스를 처리할 수 있습니다.
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
case Color.green:
print('Green as grass!');
default:
print(aColor); // Color.blue
}Code language: Dart (dart)
name 속성
.name을 호출하면 열거 상수에 해당하는 문자열 이름을 가져옵니다.
print(Color.blue.name); // 출력 "blue"Code language: Dart (dart)
열거형 사용자 정의 멤버 접근
확장 열거형은 일반 객체처럼 사용자 정의 필드, 게터, 메서드에 접근할 수 있습니다.
print(Vehicle.car.carbonFootprint);Code language: CSS (css)
다음은 이번 수업의 완성 예시입니다. 월을 표현하는 열거 클래스를 만들어 위에서 배운 내용을 활용해보겠습니다.
enum Month implements Comparable<Month> {
january(1, '一月', days: 31),
february(2, '二月', days: 28),
march(3, '三月', days: 31),
april(4, '四月', days: 30),
may(5, '五月', days: 31),
june(6, '六月', days: 30),
july(7, '七月', days: 31),
august(8, '八月', days: 31),
september(9, '九月', days: 30),
october(10, '十月', days: 31),
november(11, '十一月', days: 30),
december(12, '十二月', days: 31);
const Month(this.monthNumber, this.cnName, {required this.days});
/// 양력 월 번호 1~12
final int monthNumber;
/// 이름
final String cnName;
/// 평년 일수
final int days;
/// Getter:1분기인지 확인
bool get isFirstQuarter => monthNumber <= 3;
/// Getter:31일인 달인지 확인
bool get has31Days => days == 31;
/// 사용자 정의 메서드:윤년 2월 판단
bool isLeapYearFebruary(int year) {
if (this != Month.february) return false;
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
/// Comparable 구현으로 정렬 지원
@Override
int compareTo(Month other) {
return monthNumber - other.monthNumber;
}
}
void main() {
// 1. 기본 열거 상수 접근
Month current = Month.august;
print('현재 열거:$current');
print('열거 name 속성:${current.name}');
print('월:${current.cnName}');
print('월 번호1~12:${current.monthNumber}');
print('평년 일수:${current.days}');
print('31일 달인지:${current.has31Days}');
print('1분기인지:${current.isFirstQuarter}');
// 2. index 속성(정의 순서 인덱스, 0부터 시작)
print('\n${Month.january.name} index = ${Month.january.index}');
print('${Month.december.name} index = ${Month.december.index}');
// 3. values로 전체 열거 리스트 가져오기
List<Month> allMonths = Month.values;
print('\n총 ${allMonths.length} 개의 월');
// 4. switch에서 열거 사용
print('\n==== switch 판단 ====');
switch (current) {
case Month.january:
print('한 해의 시작');
case Month.february:
print('윤일이 존재할 수 있음');
case Month.march:
case Month.april:
case Month.may:
print('봄');
case Month.june:
case Month.july:
case Month.august:
print('여름');
case Month.september:
case Month.october:
case Month.november:
print('가을');
case Month.december:
print('겨울, 연말');
}
// 5. 사용자 정의 메서드 호출
Month feb = Month.february;
print('\n2024년 윤2월 여부:${feb.isLeapYearFebruary(2024)}');
print('2025년 윤2월 여부:${feb.isLeapYearFebruary(2025)}');
// 6. Comparable 인터페이스를 이용한 열거 정렬
var selected = [Month.october, Month.january, Month.july];
selected.sort();
print('\n정렬 후 월:${selected.map((m) => m.cnName).toList()}');
}Code language: Dart (dart)
실행 결과
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
현재 열거:Month.august
열거 name 속성:august
월:八月
월 번호1~12:8
평년 일수:31
31일 달인지:true
1분기인지:false
january index = 0
december index = 11
총 12 개의 월
==== switch 판단 ====
여름
2024년 윤2월 여부:true
2025년 윤2월 여부:false
정렬 후 월:[一月, 七月, 十月]Code language: JavaScript (javascript)
열거형