Освой Kotlin играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

when

У Kotlin есть ключевое слово when, которое заменяет оператор switch и позволяет делать более сложные вещи. Выражение when имеет больше возможностей, чем классический switch и позволяет использовать объекты.

Допустим, мы хотим создать мнемоническое правило для цветов радуги: Кот-охотник желает знать, где сидят фазаны.


fun getMnemonic(color: Color) =
    when (color) {
        Color.RED -> "кот"
        Color.ORANGE -> "охотник"
        Color.YELLOW -> "желает"
        Color.GREEN -> "знать"
        Color.BLUE -> "где"
        Color.INDIGO -> "сидят"
        Color.VIOLET -> "фазаны"
}

println(getMnemonic(Color.INDIGO))
// выводит: сидят

В примере мы создали функцию, которой присвоили значение, возвращаемое when. В Java мы так не можем писать. Нам пришлось бы создавать отдельный блок кода switch, не связанный с каким-то методом. В Kotlin такой вариант также возможен при желании.

Вам не нужно использовать break, как в Java. Для комбинирования разных веток используйте запятые.


fun getWarmth(color: Int) = when(color){
    RED, YELLOW -> "warm"
    GREEN -> "neutral"
    BLUE -> "cold"
    else -> "unknown"
}

println(getWarmth(GREEN))
// выводит: neutral

В примере используются укороченные имена цветов из перечисления Color. Перечисление вынесено в область импорта.


import android.graphics.Color.*

Вместо перечислений можно использовать и обычные переменные.

В примере используется ключевое слово else, который является аналогом default и ему передаётся значение, когда ни одно из выражений не выполнится.

Например, мы можем отслеживать видимость компонента ImageView.


button.setOnClickListener(View.OnClickListener {
    // сделаем невидимым
    catImageView.visibility = View.INVISIBLE;
    // смотрим
    when(catImageView.visibility){
        View.VISIBLE -> println("visible")
        View.INVISIBLE -> println("invisible")
        else -> println("gone")
    }
})

В предыдущих примерах возвращаемый результат присваивался функции или использовался сам по себе. Также можно присвоить и обычной переменной.


var x = 5
val result = when (x) {
    0, 1 -> "binary"
    else -> "error"
}
println(result)

В выражении when можно использовать ключевое слово is для проверки принадлежности к экземпляру класса.


fun describe(obj: Any): String =
        when (obj) {
            1 -> "Единица"
            is Cat -> "Кот!"
            "Hello Kitty" -> "Приветствуем котика"
            is Long -> "Long"
            !is String -> "Не строка"
            else -> "Unknown (Неведома зверушка)"
        }

class Cat(val name: String)

val barsik = Cat("Барсик")
println(describe(45))
println(describe("Васька"))
println(describe(475L))
println(describe(1))
println(describe(barsik))

// Результат
Не строка
Unknown (Неведома зверушка)
Long
Единица
Кот!

Можно задействовать интервалы in:


val zarplata = 1000
val cost = when (zarplata) {
    in 1..10 -> "издеваетесь?"
    in 10..100 -> "маловато будет"
    in 100..1000 -> "кота прокормлю"
    in 1000..1000000 -> "на хлеб с икрой!"
    else -> "not rated"
}
println(cost)

Следует помнить, что всегда побеждает первое условие. Поэтому нужно следить за порядком при сравнении. Допустим, мы подготовили мясо для кота. Кот готов есть мясо только определённой температуры.


val temperature = - 1

val reaction = when {
    temperature > 50 -> "Слишком горячее"
    temperature < 30 -> "Слишком холодное"
    temperature < 0  -> "Заморожено"
    else             -> "В самый раз"
}

Если температура мяса была -1, то мы получим сообщение "Слишком холодное", хотя возможно нам хотелось бы увидеть сообщение, что мясо заморожено. Но так как условие "меньше чем 30" стоит выше, чем "меньше чем 0", то сработает именно первое сообщение. Все вычисления идут сверху вниз и если встретилось подходящее условие, то дальше сравнения не происходят. Решение проблемы очень простое - нужно поменять местами выражения "меньше 0" и "меньше 30".

Ещё одно важное дополнение - when должно включать условия для всех возможных значений, т.е. должно быть исчерпывающим. Поэтому в самом конце обычно нужно включать условие else. Как правило, среда разработки предупреждает о необходимости добавить ветку else. Но в некоторых случаях, else можно опустить. Например, если речь идёт о булевых переменных, у которых есть только два значения, то написав два варианта сравнения, использовать else уже не нужно.


val isSleep = true

val action = when (isSleep) {
    true  -> "Кот спит"
    false -> "Кот не спит"
}
В Android Studio есть настройка форматирования кода при использовании when - "Align 'when' branches in columns". При включённом режиме код будет более аккуратным и читаемым

Дополнительные материалы

Примеры для строк

Реклама