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 — це не «ящики, які змінюються», а «результати обчислень». Коли ви звикаєте до цього, код стає передбачуванішим: ви читаєте його згори вниз, як рецепт.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ