Шаг 27.
Основы Kotlin.
Условные конструкции. Условное выражение when

    На этом шаге мы рассмотрим синтаксис и логику использования этой конструкции.

    Условное выражение when - еще один способ управления потоком выполнения в Kotlin. Как и if/else, оператор when позволяет писать условия и выполнять код, соответствующий истинному условию. when обеспечивает краткий синтаксис и особенно хорошо подходит для условий с тремя и более ветвями.

    Предположим, что в NyetHack игрок может быть представителем одной из выдуманных рас (race), например орком или гномом, а эти расы, в свою очередь, представляют разные фракции (faction). Оператор when берет выбранную расу и возвращает соответствующую фракцию:

    val race = "gnome"

    // Раса
    val faction = when (race) {
       "dwarf" -> "Keepers of the Mines"
       "gnome" -> "Keepers of the Mines"
       "orc" -> "Free People of the Rolling Hills"
       "human" -> "Free People of the Rolling Hills"
    }


Рис.1. Пример использования when

    Для начала объявим val race. Затем следующую переменную - faction, которой присвоим результат условного выражения when. Выражение проверяет значение race на соответствие каждому значению слева от оператора -> (стрелка) и, если находит соответствующее значение, присваивает faction значение справа (-> часто используется во многих языках и фактически имеет и другие сферы применения в Kotlin, о чем мы поговорим далее).

    По умолчанию условное выражение when действует подобно оператору сравнения == между аргументом, который вы указали в скобках, и значением, указанным в фигурных скобках. (Аргумент - это входные данные для участка кода.)

    В этом примере условного выражения when race служит аргументом, поэтому компилятор сравнит race, которое в примере имеет значение "gnome", с первым условием. Они не равны, поэтому компилятор переходит к следующему условию. Следующее сравнение вернет истинный результат, поэтому значение faction получит значение "Keepers of the Mines".


Если попробовать выполнить это приложение, то будет выдано сообщение об ошибке, говорящее, что здесь отсутствует ветвь else. В чем же дело? Неужели наличие этой ветви обязательно? Если when используется в качестве выражения (как в нашем случае), ветвь else является обязательной, если компилятор не может доказать, что все возможные случаи покрываются условиями ветвления. В нашем случае, здесь раз не перечислены все возможные случаи, поэтому, чтобы исправить эту ошибку, нужно добавить ветвь else хотя бы так:
    // Раса
    val faction = when (race) {
       "dwarf" -> "Keepers of the Mines"
       "gnome" -> "Keepers of the Mines"
       "orc" -> "Free People of the Rolling Hills"
       "human" -> "Free People of the Rolling Hills"
        else -> ""
    }

    Теперь, когда вы увидели преимущества условного выражения when, удалите логику вычисления healthStatus. В отличие от прежде использовавшегося оператора if/else, оператор when делает код более простым и компактным. На практике применяется простое эмпирическое правило: используйте оператор when, если if/else содержит ветви else if.

    Обновите логику healthStatus, используя when.

    val healthStatus = when (healthPoints) {
        100 -> "is in excellent condition!"
        in 90..99 -> "has a few scratches."
        in 75..89 -> if (isBlessed) {
            "has some minor wounds but is healing quite quickly!"
        } else {
            "has some minor wounds."
        }
        in 15..74 -> "looks pretty hurt."
        else -> "is in awful condition!"
    }
Файл с проектом можно взять здесь.


Рис.2. Рефакторинг кода healthStatus с оператором when (Game.kt)

   

    Условное выражение when работает так же, как условное выражение if/else, определяя условия и выполняя ветви, где эти условия истинны. when отличается тем, что автоматически выбирает условие слева, соответствующее значению аргумента в области видимости. Подробнее мы поговорим про область видимости чуть позже. Рассмотрим кратко условное выражение in 90..99.

    Вы уже видели, как использовать ключевое слово in для проверки принадлежности значения интервалу, и то же происходит здесь: проверяем значение healthPoints, хотя и не упоминаем об этом явно. В области видимости интервала, слева от ->, находится переменная healthPoints, поэтому компилятор вычислит оператор when, как если бы healthPoints входила в каждое условие ветвления.

    Часто when лучше передает логику кода. В этом случае, чтобы получить тот же результат с помощью оператора if/else, потребуется добавить три ветви else if. Оператор when делает это более простым способом.

    Условное выражение when обеспечивает большую гибкость, чем оператор if/else, при сопоставлении с заданными условиями. Большинство условий слева вычисляются как истинные или ложные, другие ограничиваются простым сравнением, как в примере с условием 100. Условный оператор when может выразить любое из них, как показано в примере выше. Кстати, можно ли заменить вложенный оператор if/else в одной из ветвей условного выражения when? Такая конструкция встречается не часто, но гибкость when позволяет реализовать ее.

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

    На следующем шаге мы рассмотрим шаблонные строки.




Предыдущий шаг Содержание Следующий шаг