스물네 번째, enum 클래스입니다.
enum 클래스의 가장 기본적인 사용 사례는 타입에 안전한 열거형을 구현하는 것입니다.
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
각각의 enum 상수는 객체입니다. enum 상수는 콤마로 구분합니다.
각각의 enum은 enum 클래스의 인스턴스이며, 다음과 같이 초기화할 수 있습니다.
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
익명 클래스
enum 상수는 각각 자신의 메소드가 있는 익명 클래스를 가질 수 있습니다. 그리고, 기본 메소드를 오버라이딩 할 수도 있습니다.
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
}; // 상수 부분과 아래 멤버 정의를 세미콜론으로 구분
abstract fun signal(): ProtocolState
}
만약 enum 클래스가 어떤 멤버를 정의한다면, 상수 정의와 멤버 정의를 세미콜론으로 구분합니다.
enum 클래스에서 인터페이스 구현
enum 클래스는 인터페이스를 구현할 수 있습니다(하지만, 클래스로부터 파생될 수는 없습니다). 모든 항목을 위해 인터페이스 멤버들에 대한 공통 구현을 작성하거나, 익명 클래스를 통해서 항목 각각의 개별적인 구현을 작성할 수 있습니다. 인터페이스 구현은 다음의 예에서 보여주는 것처럼 구현하기 원하는 인터페이스를 enum 클래스 선언에 추가하여 구현합니다.
import java.util.function.BinaryOperator
import java.util.function.IntBinaryOperator
enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator {
// BinaryOperator는 개별 구현한 예
PLUS {
override fun apply(t: Int, u: Int): Int = t + u
},
TIMES {
override fun apply(t: Int, u: Int): Int = t * u
};
// IntBinaryOperator는 공통 구현한 예
override fun applyAsInt(t: Int, u: Int) = apply(t, u)
}
fun main() {
val a = 13
val b = 31
for (f in IntArithmetics.entries) {
println("$f($a, $b) = ${f.apply(a, b)}")
}
}
/* 결과
PLUS(13, 31) = 44
TIMES(13, 31) = 403
*/
모든 enum 클래스는 기본적으로 Comparable 인터페이스를 구현합니다. 이로 인해 enum 클래스 상수들은 자연스러운 순서 정의를 갖게 됩니다. 순서와 관련된 내용을 참고하시기 바랍니다.
enum 상수를 가지고 작업하기
Kotlin의 enum 클래스는 정의된 상수들을 나열하고, 이름으로 enum 상수를 얻을 수 있는 프로퍼티와 메소드를 가지고 있습니다. 이러한 메소드들의 시그니처는 다음과 같습니다(enum 클래스의 이름이 EnumClass라고 가정합니다).
EnumClass.valueOf(value: String): EnumClass
EnumClass.entries: EnumEntries<EnumClass> // 특화된 List<EnumClass>
다음은 동작하는 예입니다.
enum class RGB { RED, GREEN, BLUE }
fun main() {
for (color in RGB.entries) println(color.toString()) // 출력: RED, GREEN, BLUE
println("The first color is: ${RGB.valueOf("RED")}") // 출력: "The first color is: RED"
}
/* 결과
RED
GREEN
BLUE
The first color is: RED
*/
vaueOf() 메소드는 주어진 이름과 일치하는 enum 상수를 찾지 못했을 때 IllegalArgumentException을 던집니다.
Kotlin 1.9.0에서 entries가 소개되기 전까지는 enum 상수들의 배열을 얻는데 values() 메소드가 사용됐습니다.
또한, 모든 enum 상수는 name과 ordinal이라는 프로퍼티를 가지고 있는 데, 이를 통해 각각 이름과 enum 클래스 선언에서의 (0부터 시작하는) 위치를 얻을 수 있습니다.
enum class RGB { RED, GREEN, BLUE }
fun main() {
println(RGB.RED.name) // RED 출력
println(RGB.RED.ordinal) // 0 출력
}
enumValues<T>()와 enumValueOf<T>() 함수를 사용하여 enum 클래스의 상수들을 제네릭한 방법으로 접근할 수 있습니다.
enum class RGB { RED, GREEN, BLUE }
inline fun <reified T : Enum<T>> printAllValues() {
println(enumValues<T>().joinToString { it.name })
}
printAllValues<RGB>() // prints RED, GREEN, BLUE
※ 인라인 함수와 구체화된(reified) 타입 매개변수에 대한 보다 자세한 정보는 인라인 함수를 참고하세요.
Kotlin 1.9.20에서 추후 enumValues<T>()를 대체할 enumEntries<T>() 함수가 소개됐습니다.
enumValues<T>()는 여전히 지원되지만, enumEntries<T>()를 대신 사용할 것을 추천합니다(추천은 하고 있지만, 아래에 적혀 있는 것처럼 아직 실험 단계입니다). 왜냐하면 enumEntries<T>()가 성능 면에서 더 낫기 때문입니다. enumValues<T>() 호출할 때마다 매 번 새로운 배열이 생성됩니다. 이에 반해, enumEntries<T>()는 호출할 때마다 매번 같은 리스트를 반환하기 때문에 보다 효율적입니다.
예
enum class RGB { RED, GREEN, BLUE }
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Enum<T>> printAllValues() {
println(enumEntries<T>().joinToString { it.name })
}
printAllValues<RGB>()
// RED, GREEN, BLUE
※ enumEntries<T>() 함수는 실험 단계입니다. 이를 사용하기 위해서는 @OptIn(ExperimentalStdlibApi)를 통해 사용 동의를 받아야하고, 언어 버전이 적어도 1.9 이상으로 설정되어야 합니다.
'Kotlin' 카테고리의 다른 글
공식 문서로 배우는 코틀린 - 26. Object expressions and declarations (0) | 2024.03.12 |
---|---|
공식 문서로 배우는 코틀린 - 25. Inline value classes (0) | 2024.03.11 |
공식 문서로 배우는 코틀린 - 23. Nested and inner classes (0) | 2024.03.11 |
공식 문서로 배우는 코틀린 - 22. Generics: in, out, where (0) | 2024.03.11 |
공식 문서로 배우는 코틀린 - 21. Sealed classes and interfaces (0) | 2024.03.10 |