JavaRush /Курси /Kotlin SELF /if як вираз у Kotlin: присвоюємо результат розгалуження

if як вираз у Kotlin: присвоюємо результат розгалуження

Kotlin SELF
Рівень 3 , Лекція 5
Відкрита

1. Вступ

Якщо ви щойно опанували if, голова ще може сприймати його як «перехрестя»: якщо умова істинна — йдемо ліворуч і щось робимо, інакше — праворуч і теж щось робимо. І це нормально. Та в реальних програмах нам часто потрібно не лише «виконати дію», а отримати результат вибору: рядок, число, мітку — те, що потім використаємо далі.

Уявіть, що ви обираєте, яку табличку повісити на двері: "Відчинено" або "Зачинено". Це не окрема дія заради дії — це значення, яке потрібно зберегти й потім вивести. Kotlin у такій ситуації каже: «Гаразд, нехай if одразу повертає табличку». І це дуже зручно.

if як оператор і if як вираз

Коли ми пишемо if «по-старому», він працює як оператор (statement): виконує або не виконує фрагмент коду — і на цьому все.

Але Kotlin дозволяє використовувати if як вираз (expression), тобто як конструкцію, що має значення — як у 3 + 4 або в "Hi".length. Це офіційна частина мови: if можна писати як вираз і присвоювати його результат змінній. Але тоді гілка else стає обовʼязковою.

Щоб уловити ідею, порівняймо два стилі: «спочатку завів коробку (var), а потім поклав туди результат» і «одразу отримав результат».

Ось стиль, який ви вже знаєте (операторний if):

fun main() {
    val temperature = 28

    var label = "Нормально"
    if (temperature > 25) {
        label = "Спекотно"
    }

    println(label) // Спекотно
}

Тут if нічого «не повертає». Ми просто змінюємо label.

А ось стиль, який ми хочемо опанувати сьогодні (вираз if):

fun main() {
    val temperature = 28

    val label = if (temperature > 25) "Спекотно" else "Нормально"
    println(label) // Спекотно
}

Різниця за змістом така: у другому варіанті ми прямо кажемо Kotlin: «label — це результат вибору».

Базовий синтаксис: val x = if (cond) A else B

Базова форма така: val result = if (умова) значення1 else значення2. Читається вона майже як звичайна фраза: «result дорівнює (якщо умова — значення1, інакше — значення2)».


val result = if (condition) value1 else value2
Базовий синтаксис: if як вираз

Приклад, який зазвичай добре «заходить», — модуль числа (абсолютне значення). У математиці це |x|, а в коді ми просто обираємо: або x, або -x.

fun main() {
    val x = -7

    val abs = if (x >= 0) x else -x
    println("abs = $abs") // abs = 7
}

Зверніть увагу: тут ми взагалі не використовуємо var. Це маленька, але важлива перемога: менше змінних, які можна змінювати, — менше місць, де можна «випадково все зламати».

Чому else обовʼязковий

З погляду новачка вимога «чому я не можу написати val r = if (cond) 1?» може здаватися прискіпуванням. Але компілятор не шкідничає — він дбає про логіку. Якщо ви присвоюєте результат, то він має існувати завжди, незалежно від того, яким буде результат умови.

У Kotlin прямо сказано: якщо if використовується як вираз, гілка else обовʼязкова.

Поганий приклад (так не можна):

fun main() {
    val isVip = true
    val discount = if (isVip) 10 // Помилка компіляції: немає else
}

Хороший приклад (так правильно):

fun main() {
    val isVip = true

    val discount = if (isVip) 10 else 0
    println("discount = $discount") // discount = 10
}

Тут зручно запамʼятати правило: якщо if стоїть праворуч від = і ви хочете зберегти результат, то else завжди обовʼязковий.

Гілки-блоки { ... }: значення — це останній вираз

Часто в гілці потрібно виконати не одну дію. Наприклад, надрукувати пояснення, а вже потім повернути значення. Kotlin дозволяє, щоб кожна гілка була блоком { ... }. Тоді результатом гілки стає останній вираз у блоці.

Зробімо мініприклад: обираємо, кого вважати «вищим» — Алісу чи Боба. Паралельно виводимо, кого обрали (ніби ведемо журнал).

fun main() {
    val heightAlice = 160
    val heightBob = 175

    val taller = if (heightAlice > heightBob) {
        println("Вибрали Алісу") // Вибрали Алісу (якби умова була true)
        heightAlice
    } else {
        println("Вибрали Боба")  // Вибрали Боба
        heightBob
    }

    println("taller = $taller") // taller = 175
}

Зауважте «фокус»: println(...) — це не значення для taller. Значення — це останній рядок гілки (heightAlice або heightBob).

Це дуже важлива звичка: наприкінці гілки if-виразу має стояти саме те, що ви хочете повернути.

Невеличка схема: як це працює

flowchart TD
    A["if (умова)"] -->|true| B["гілка then { ... }"]
    A -->|false| C["гілка else { ... }"]
    B --> D["значення = останній вираз гілки then"]
    C --> E["значення = останній вираз гілки else"]
    D --> F["підсумок if-виразу"]
    E --> F

2. else if і лінійний стиль коду

Іноді в нас не «два варіанти», а «три-чотири». І гарна новина: ланцюжок if / else if / else теж може бути виразом. Тобто ми можемо присвоїти результат одразу, без проміжних var.

Приклад: маємо число x і хочемо отримати рядок "positive", "negative" або "zero".

fun main() {
    val x = 0

    val sign = if (x > 0) {
        "positive"
    } else if (x < 0) {
        "negative"
    } else {
        "zero"
    }

    println(sign) // zero
}

Цей стиль особливо добрий тим, що зміст змінної sign одразу зрозумілий: «це мітка знака числа».

Як if-вираз допомагає робити код «лінійним»

До появи звички використовувати if-вирази часто пишуть так: «оголосив змінну var, а потім у різних гілках присвоюю». Це робочий підхід, але поступово він призводить до того, що змінна живе надто довго й змінюється надто багато разів.

Порівняймо два підходи на простій життєвій задачі: якщо рядок порожній — замінити його на "EMPTY", інакше залишити як є (після trim()).

Підхід із var:

fun main() {
    val raw = "   Kotlin   "
    val trimmed = raw.trim()

    var label = "EMPTY"
    if (trimmed.length != 0) {
        label = trimmed
    }

    println(label) // Kotlin
}

Підхід із if-виразом:

fun main() {
    val raw = "   Kotlin   "
    val trimmed = raw.trim()

    val label = if (trimmed.length == 0) "EMPTY" else trimmed
    println(label) // Kotlin
}

Другий варіант читається швидше: «label — це або "EMPTY", або trimmed». І головне: label тепер val. А отже «табличку на дверях» не можна випадково змінити посеред програми.

3. Практичний приклад: «Каса зі знижкою»

Зараз ми зберемо невелику консольну програму, яка схожа на реальний сценарій: користувач вводить суму замовлення, а ми рахуємо знижку й друкуємо підсумок. Це чесний тренажер, на якому добре видно, як if як вираз робить код простішим.

Ідея така:

1) читаємо суму (як рядок), прибираємо зайві пробіли, намагаємося перетворити на число через toIntOrNull();
2) якщо це не число — друкуємо повідомлення про помилку;
3) якщо це число — визначаємо відсоток знижки: якщо сума >= 1000, то знижка 10 %, інакше 0 %;
4) формуємо повідомлення й друкуємо.

Крок 1. Обираємо відсоток знижки як значення

Почнемо з найважливішого для цієї лекції — присвоювання результату розгалуження:

fun main() {
    val sum = 1200

    val discountPercent = if (sum >= 1000) 10 else 0
    println("discountPercent = $discountPercent") // discountPercent = 10
}

Тут видно головне: discountPercent — це результат вибору. Отже, if-вираз підходить ідеально.

Крок 2. Повідомлення теж можна «обчислити»

Новачки часто роблять так: у кожній гілці if друкують майже однаковий текст. Це працює, але швидко призводить до дублювання. Натомість можна обчислити рядок message, а друк залишити одним рядком.

fun main() {
    val finalSum = 950
    val discountPercent = 0

    val message = if (discountPercent > 0) {
        "Знижка $discountPercent% застосована. Підсумок: $finalSum"
    } else {
        "Знижки немає. Підсумок: $finalSum"
    }

    println(message) // Знижки немає. Підсумок: 950
}

Зверніть увагу: ми використовуємо блоки { ... }, але останній рядок — це саме рядок, а не println.

Крок 3. Повна версія main

Нижче — цілісний приклад. Він трохи довший за окремі фрагменти (бо реальна програма все-таки робить введення й перевірки), але всі прийоми тут уже знайомі.

fun main() {
    print("Введіть суму замовлення: ")
    val sumText = readln().trim()
    val sum = sumText.toIntOrNull()

    if (sum == null) {
        println("Помилка: потрібно ввести ціле число.") // Помилка: потрібно ввести ціле число.
    } else {
        val discountPercent = if (sum >= 1000) 10 else 0
        val discount = sum * discountPercent / 100
        val finalSum = sum - discount

        val message = if (discountPercent > 0) {
            "Знижка $discountPercent% (-$discount). Підсумок: $finalSum"
        } else {
            "Знижки немає. Підсумок: $finalSum"
        }

        println(message) // приклад: Знижка 10% (-120). Підсумок: 1080
    }
}

Тут важливий стиль мислення: ми намагаємося робити змінні «одноразовими фактами». discountPercent, discount, finalSum, message — це не «ящики, які змінюються», а «результати обчислень». Коли ви звикаєте до цього, код стає передбачуванішим: ви читаєте його згори вниз, як рецепт.

1
Опитування
Умовні оператори та логіка, рівень 3, лекція 5
Недоступний
Умовні оператори та логіка
Умовні оператори та логіка
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ