1. Навіщо потрібен if let
Коли ви вперше бачите String?, може здатися, ніби Swift спеціально ускладнює життя. В інших мовах ви б просто взяли рядок, а якщо його немає — «ну, якось потім розберемося» (найчастіше вже пізно вночі, у продакшені, з кавою та легкою панікою). Swift змушує зустрітися з проблемою раніше. Зате й простіше: компілятор не дає вам удавати, що значення точно є.
Суть Optional дуже проста: тип T? означає «або значення типу T, або відсутність значення (nil)». І головне: T? — це не те саме, що T. Тому, перш ніж працювати зі «звичайним» значенням, ми маємо передбачити поведінку на випадок nil. Найпряміший спосіб — зв’язування значень Optional через if let.
Базовий синтаксис if let
Якщо сказати простіше, if let читається так: «якщо в цій змінній справді лежить значення, тоді витягни його і дай мені у вигляді звичайного типу без ?». Тобто ми не просто перевіряємо, а створюємо нову змінну всередині блока, яка вже не містить ?.
Найкласичніша форма має такий вигляд:
let maybeAge: Int? = Int("21")
if let age = maybeAge {
print("Вік: \(age)") // Вік: 21
} else {
print("Вік невідомий")
}
Зверніть увагу: всередині блока if змінна age має тип Int, а не Int?. Саме в цьому і полягає головна зручність if let: далі код читається спокійно, без танців навколо nil.
2. Область видимості й робота з Optional
Чому не можна використовувати String? як String
На цьому місці зазвичай трапляється діалог:
«Swift, ну я ж бачу, що там рядок!»
«А я — ні. І я не телепат.»
Подивімося на типову ситуацію:
let line: String? = readLine()
print(line.count) // ❌ так не можна
Компілятор не дасть вам викликати .count, тому що в String? немає властивості count. У нього є два стани: «є рядок» і «рядка немає». Коли рядка немає, .count просто не має сенсу.
Правильний шлях — витягнути значення:
let line: String? = readLine()
if let text = line {
print(text.count)
} else {
print("Введення відсутнє")
}
if let тут перетворює невизначену ситуацію («може бути рядок, може бути ні») на визначену: в одній гілці рядок точно є, в іншій — ми явно обробили відсутність.
Чому змінна з if let «зникає»
Спочатку це здається дивним: «Я ж щойно створив text, чому я не можу використовувати його далі?». Але тут усе логічно: змінна, створена в if let, живе лише всередині блока, тому що тільки там гарантовано існує значення.
Приклад:
let maybeName: String? = readLine()
if let name = maybeName {
print("Привіт, \(name)!")
}
// print(name) // ❌ name не існує тут
Swift ніби говорить: «Поза межами if я вже не гарантую, що значення було». Тому й не дає вам цієї змінної.
Затінення і коротка форма if let name
Тепер цікавий момент: дуже часто optional-змінна й «розгорнута» змінна логічно є одним і тим самим значенням, лише в різних станах. У Swift поширений патерн if let foo = foo, тобто «створи нову змінну з тим самим іменем, але вже без ?». Саме тому, що це трапляється дуже часто, у Swift зʼявився скорочений запис: if let foo { ... } — це синтаксичний цукор для if let foo = foo { ... }.
Приклад:
let name: String? = readLine()
if let name {
// Тут name: String (без ?), і він затіняє зовнішню optional-змінну name: String?
print("Імʼя: \(name)")
} else {
print("Імʼя не введено")
}
Важливо розуміти ідею: це нова змінна всередині блока, а не «магічне перетворення типу». У Swift optional binding створює окреме значення в новій області видимості — це принципова частина моделі мови.
3. Кілька Optional і додаткові перевірки
Кілька Optional в одній умові
Частий біль новачка — «сходинки» з вкладених if:
let line = readLine()
if let line {
let n = Int(line)
if let n {
print(n * 2)
} else {
print("Не число")
}
} else {
print("Немає введення")
}
Працює, але виглядає як під’їзд без ліфта. На щастя, Swift дає змогу витягувати кілька значень в одній умові через кому. Це підтримується синтаксисом умов if/guard/while: можна поєднувати зв’язування Optional і булеві перевірки в одному блоці.
Ось читабельніший варіант:
if let line = readLine(),
let n = Int(line) {
print(n * 2)
} else {
print("Введіть ціле число")
}
Тут ми робимо дві перевірки поспіль: «рядок взагалі прийшов» і «рядок успішно перетворився на число». Якщо щось не так — переходимо в else.
if let плюс смислові умови
Іноді мало просто «чи є значення». Ми хочемо, щоб воно було ще й «правильним» за логікою: додатним, непорожнім, у діапазоні тощо. Swift дає змогу додавати звичайні булеві умови до того самого списку через кому. Це один із тих моментів, де читабельність залежить від міри: 2–3 умови зазвичай нормально, а 10 умов перетворюють код на ребус.
Приклад: читаємо число і переконуємося, що воно додатне.
if let line = readLine(),
let n = Int(line),
n > 0 {
print("Додатне число: \(n)")
} else {
print("Потрібно ввести додатне ціле число")
}
Це працює тому, що умовні конструкції в Swift сприймають список перевірок як послідовність кроків, розділених комами.
4. Мінісхема: що робить if let
Щоб не сприймати if let як магічне закляття, корисно тримати в голові один і той самий шаблон: Swift намагається «дістати» значення з коробки. Якщо коробка порожня (nil) — переходимо в else.
flowchart TD
A["Є Optional, наприклад Int?"] --> B{"Він nil?"}
B -- "Так" --> C["else: обробляємо відсутність значення"]
B -- "Ні" --> D["if: створюємо нову змінну без '?'"]
D --> E["Працюємо як зі звичайним Int або String"]
5. Приклад: консольний «TipBuddy»
Щоб тема не залишилася «у вакуумі», давайте зберемо невеликий застосунок, який ми зможемо вдосконалювати в наступних лекціях цього рівня. Ідея проста: користувач вводить суму рахунку й відсоток чайових, а застосунок друкує підсумок. Ця вправа ідеально підходить для if let, тому що введення може бути відсутнім, а перетворення рядка на число може не спрацювати.
Крок 1: читаємо суму рахунку як Double
Спочатку зробимо найпряміший варіант: одне введення — одна перевірка — один розрахунок.
import Foundation
print("Введіть суму рахунку:")
let billLine = readLine()
if let billLine,
let bill = Double(billLine) {
print("Рахунок: \(bill)")
} else {
print("Сума введена некоректно")
}
Зверніть увагу: Double(billLine) повертає Double?, тому ми витягуємо і рядок, і число.
Крок 2: додаємо відсоток чайових
Тепер потрібно два значення. І тут якраз спрацьовує комбінований прийом if let ... , let ....
import Foundation
print("Сума рахунку:")
let billLine = readLine()
print("Відсоток чайових (наприклад 10):")
let tipLine = readLine()
if let billLine,
let bill = Double(billLine),
let tipLine,
let tipPercent = Double(tipLine) {
let total = bill + bill * tipPercent / 100
print("Разом: \(total)")
} else {
print("Помилка введення: потрібно ввести два числа")
}
Так, умова стала довшою. Але вона все ще лінійна: ми читаємо зверху вниз і бачимо, які кроки мають виконатися.
Крок 3: додамо смислову перевірку
Трохи предметної логіки: відʼємні чайові — це вже не калькулятор, а соціальний експеримент. Додамо перевірку:
import Foundation
print("Сума рахунку:")
let billLine = readLine()
print("Відсоток чайових:")
let tipLine = readLine()
if let billLine,
let bill = Double(billLine),
bill >= 0,
let tipLine,
let tipPercent = Double(tipLine),
tipPercent >= 0 {
let total = bill + bill * tipPercent / 100
print("Разом: \(total)")
} else {
print("Введіть невід’ємні числа")
}
Тут важливо помітити: булеві перевірки (bill >= 0) ідуть поруч із перевірками зв’язування, і це нормальний стиль Swift.
6. Наводимо лад: виносимо читання числа у функцію
Коли ви пишете консольні застосунки, швидко з’являється повторюваний код: «попросити введення → прочитати рядок → спробувати перетворити на число → якщо не вдалося, повідомити». Це чудовий момент, щоб застосувати функції й зробити код трохи охайнішим.
Зробимо функцію, яка намагається прочитати Double і повертає Double?. Це чесний контракт: «може спрацювати, а може й ні».
import Foundation
func readDouble(prompt: String) -> Double? {
print(prompt)
let line = readLine()
if let line, let value = Double(line) {
return value
} else {
return nil
}
}
Тепер основний код простіший:
import Foundation
let bill = readDouble(prompt: "Сума рахунку:")
let tip = readDouble(prompt: "Відсоток чайових:")
if let bill,
let tip,
bill >= 0,
tip >= 0 {
let total = bill + bill * tip / 100
print("Разом: \(total)")
} else {
print("Помилка: перевірте введення")
}
Тут ми використовуємо той самий прийом, який обговорювали вище: if let bill { ... } — скорочення для if let bill = bill { ... }, тобто вилучення зі затіненням імені.
Якщо ця коротка форма поки що плутає вас — можна писати довгу. Це нормально. Головне, щоб ви розуміли, що відбувається.
7. Читабельність: типові патерни if let
Коли ви лише опановуєте зв’язування Optional, найімовірніше, будете писати або занадто багато вкладеності, або занадто багато «розумної компактності». Ні те ні інше не смертельно, але читабельність — це навичка, яка зростає швидше, якщо помічати патерни.
| Ситуація | Менш вдало | Зазвичай читабельніше |
|---|---|---|
| Два Optional поспіль | вкладений if всередині if | if let a = ..., let b = ... {} |
| Хочемо «те саме імʼя» | if let x = x {} (багато повторів) | if let x {} (коротше) |
| Перевірка й вилучення | if x != nil { x! } | if let x { ... } (без ризику) |
8. Типові помилки під час роботи з if let
Помилка №1: намагатися «дотиснути» компілятор замість того, щоб обробити nil.
Новачок часто бачить, що тип став String?, і починає боротися з питальним знаком, ніби це помилка: «Ну, давай я якось перетворю це на String». Але Optional — це не перешкода, а підказка про реальність даних. Якщо введення може бути відсутнім, для цього випадку має бути окремий сценарій у застосунку. if let саме про це: обрати поведінку для nil, а не вдавати, що його не буває.
Помилка №2: використовувати змінну з if let поза блоком.
Це дуже часте «чому Swift такий суворий?». Змінна, створена в if let, живе у своїй області видимості, тому що тільки там гарантовано наявність значення. Якщо вам потрібно використовувати її далі, це зазвичай знак, що структуру коду варто перебудувати: перенести використання всередину if або винести логіку у функцію, яка повертає звичайний результат.
Помилка №3: робити «сходи» з вкладених if, хоча можна об’єднати умови.
Вкладені if let технічно коректні, але вони швидко роздувають код і ускладнюють читання. Swift дає змогу витягувати кілька значень в одній умові через кому, і це один із найкорисніших прийомів для початківця.
Помилка №4: плутати скорочений if let x зі «зміною типу змінної».
Скорочення if let x { ... } — це просто цукор для if let x = x { ... }. Усередині блока створюється нова змінна, яка затіняє зовнішню optional-змінну з тим самим іменем. Це не магічне «перемикання типу», а цілком конкретне оголошення нової змінної в новій області видимості.
Помилка №5: перетворювати умову на простирадло з 12 перевірок.
Swift дає змогу поєднувати зв’язування й булеві умови в одному if, і це потужно. Але якщо умова перетворюється на пів екрана, мозок читача починає «підвисати». У такій ситуації краще зробити кілька проміжних змінних або винести частину логіки в невелику функцію — особливо якщо перевірка має смислову назву («валідний відсоток», «непорожній рядок» тощо).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ