Menu
Coddy logo textTech

Классы перечислений

Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 33 из 57.

enum class объявляет тип с фиксированным набором значений — его константами. Каждая константа является объектом перечисления с name и ordinal — её позицией, начинающейся с 0. entries перечисляет их по порядку:

enum class Direction { NORTH, EAST, SOUTH, WEST }

Внутри main:

val d = Direction.EAST
println(d)
println(d.ordinal)
println(Direction.entries)

Вывод:

EAST
1
[NORTH, EAST, SOUTH, WEST]

Константы перечисления могут иметь свойства, передаваемые конструктору перечисления, а перечисление может объявлять методы. Точка с запятой завершает список констант перед членами:

enum class Coin(val cents: Int) {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    fun label() = "${name.lowercase()} ($cents c)"
}

Внутри main:

println(Coin.DIME.label())
println(Coin.entries.sumOf { it.cents })

Вывод:

dime (10 c)
41

Для when над перечислением, в котором перечислены все константы, else не требуется, а компилятор сообщает, если какая-либо константа пропущена. valueOf("SOUTH") находит константу по её точному имени и выдаёт исключение для неизвестного имени, поэтому входные данные обычно сопоставляют с помощью entries.find:

enum class Direction { NORTH, EAST, SOUTH, WEST }

fun turnRight(d: Direction) = when (d) {
    Direction.NORTH -> Direction.EAST
    Direction.EAST -> Direction.SOUTH
    Direction.SOUTH -> Direction.WEST
    Direction.WEST -> Direction.NORTH
}

fun parse(text: String) = Direction.entries.find { it.name == text.uppercase() }

Внутри main:

println(turnRight(Direction.valueOf("SOUTH")))
println(parse("north"))
println(parse("up"))

Результат:

WEST
NORTH
null

Константа может иметь собственное тело и переопределять в нём метод. Объявление метода abstract в перечислении заставляет каждую константу реализовать его:

enum class Op(val symbol: String) {
    PLUS("+") {
        override fun apply(a: Int, b: Int) = a + b
    },
    TIMES("*") {
        override fun apply(a: Int, b: Int) = a * b
    };

    abstract fun apply(a: Int, b: Int): Int
}

Внутри main:

for (op in Op.entries) println("6 ${op.symbol} 3 = ${op.apply(6, 3)}")

Результат:

6 + 3 = 9
6 * 3 = 18
challenge icon

Задание

Легко

Завершите перечисление Size константами SMALL (250 мл, цена 300), MEDIUM (350 мл, 380) и LARGE (500 мл, 450); цены указаны в центах. label() возвращает medium (350 ml): 3.80, а upsize() возвращает следующий больший размер или тот же размер для LARGE. parse(text) companion-объекта находит размер по его имени без учёта регистра или по его первой букве (s, M), а в противном случае возвращает null.

Предоставленный код считывает заказы, такие как medium, L или up small (напиток увеличенного размера), и выводит каждую метку или unknown size x, а в конце — total: 11.10.

Ваш код должен находиться в Size.kt. В Main.kt содержится предоставленный код ввода/вывода, и его нельзя изменять.

Попробуйте сами

fun main() {
    // Предоставленный код ввода/вывода: оставьте его как есть
    val input = generateSequence(::readLine).toList()
    var total = 0
    for (line in input) {
        val upsize = line.startsWith("up ")
        val size = Size.parse(line.removePrefix("up "))
        if (size == null) {
            println("unknown size $line")
            continue
        }
        val chosen = if (upsize) size.upsize() else size
        println(chosen.label())
        total += chosen.price
    }
    println("total: %d.%02d".format(total / 100, total % 100))
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Песочница Kotlin