Классы перечисления #

Васильев Андрей Михайлович, 2024

Версии презентации

Описание классов-перечислений #

Наиболее базовый пример использования классов-перечислений — это реализация типобезопасных перечислений

enum class Direction {
    NORTH, SOUTH, WEST, EAST
    ;
}
  • Каждая константа перечисления является объектом
  • При объявлении константы разделяются запятыми
  • Перечисление констант завершается точкой с запятой
  • После точки с запятой идёт описание функций-членов и объектов-компаньонов

Данные констант #

Так как константы являются экземплярами enum-класса, они могут быть инициализированы

enum class Color(val rgb: Int, val description: String) {
    RED(0xFF0000, "Красный"),
    GREEN(0x00FF00, "Зелёный"),
    BLUE(0x0000FF, "Синий"),
    ;
}

К полям объекта можно обращаться как к обычным полям

val color = Color.GREEN
println(color.description)

Стандартные данные констант #

Каждая enum-константа имеет поля, в которых содержатся её имя и порядковый номер в объявлении enum-класса

Вы не можете переопределить данные поля

val name: String
val ordinal: Int

Также enum-константы реализуют интерфейс Comparable. Порядок сортировки соответствует порядку объявления

println(RGB.RED.name)    // prints RED
println(RGB.RED.ordinal) // prints 0

Работа с enum-константами #

Enum-классы в Kotlin имеют синтетические методы для вывода списка объявленных enum-констант и для получения enum-константы по её имени

enum class RGB { RED, GREEN, BLUE }

RGB.valueOf(value: String): RGB
RGB.entries: EnumEntries<RGB>

Метод valueOf() выбрасывает исключение IllegalArgumentException, если указанное имя не соответствует ни одной enum-константе, объявленной в классе

fun main() {
    for (color in RGB.entries) println(color.toString()) 
    println("The first color is: ${RGB.valueOf("RED")}")
}

В Kotlin до 1.8 вместо entries предоставлялся метод values(), который возвращал новый массив из констант

Обобщённый доступ к константам #

К константам в enum-классе можно получить доступ универсальным способом, используя функции enumEntries() и enumValueOf():

inline fun <reified T : Enum<T>> printAllValues() {
    print(enumEntries<T>().joinToString { it.name })
}

printAllValues<RGB>() // выведет RED, GREEN, BLUE

В Kotlin до 1.8 вместо enumEntries<T>() предоставлялся метод enumValues<T>(), который также возвращает новый массив из констант

Условное выражение when #

when определяет условное выражение с несколькими «ветвями». Оно похоже на оператор switch, присутствующий в C-подобных языках.

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // обратите внимание на блок
        print("x не равен ни 1, ни 2")
    }
}

when последовательно сравнивает свой аргумент со всеми указанными значениями, пока не выполнится какое-либо из условий ветвей.

Полнота вычислений #

Если when используется как выражение, то ветка else является обязательной, за исключением случаев, в которых компилятор может убедиться, что ветки покрывают все возможные значения

Так происходит, например с записями классов-перечислений

enum class Bit {
  ZERO, ONE
}
val numericValue = when (getRandomBit()) {
    Bit.ZERO -> 0
    Bit.ONE -> 1
    // 'else' не требуется, потому что все случаи учтены
}

В операторах when ветка else является обязательной в следующих условиях:

  • when имеет объект типа Boolean, enum, sealed или их nullable-аналоги
  • ветки when не охватывают все возможные случаи для этого объекта