1. Навіщо взагалі потрібен switch, якщо є if/else
Коли ви тільки починаєте програмувати, здається, що if/else — це відповідь майже на всі запитання. Потрібно перевірити команду? if. Потрібно обробити три варіанти? else if. Потрібно обробити десять варіантів? Ну… «тоді ще вісім else if» — і ось тут уже починаються сумні зітхання. switch у Swift створений як читабельніший спосіб розгалуження, коли варіантів багато й усі вони пов’язані з одним конкретним значенням.
Уявіть простий сценарій: користувач вводить текстову команду, а ви хочете реагувати на неї.
Через if/else if це швидко перетворюється на «сходинку»:
import Foundation
let command = (readLine() ?? "").lowercased()
if command == "help" {
print("Показати довідку") // Показати довідку
} else if command == "exit" {
print("Вихід") // Вихід
} else if command == "version" {
print("Версія 0.1") // Версія 0.1
} else {
print("Невідома команда") // Невідома команда
}
Код працює, але є проблема: він читається як ланцюжок порівнянь, а не як «вибір гілки за значенням».
switch дозволяє читати це майже як меню: «якщо "help" — сюди, якщо "exit" — туди, інакше — ось так».
2. Анатомія switch: як він влаштований
У switch усе побудовано на простій ідеї: ми беремо одне значення і зіставляємо його з набором варіантів. Важливо розуміти: switch — це не «розумний if», а окрема конструкція зі своїм стилем. Якщо if — це «перевіримо умову», то switch — це «підберемо для значення відповідний шаблон».
Базова форма виглядає так:
switch someValue {
case ...:
// дії
case ...:
// дії
default:
// дії «про всяк випадок»
}
Давайте візьмемо мініприклад: «номер дня тижня → коротка назва».
import Foundation
let dayNumber = 3
switch dayNumber {
case 1:
print("Mon") // Mon
case 2:
print("Tue") // Tue
case 3:
print("Wed") // Wed
default:
print("Unknown") // Unknown
}
Тут важливо запамʼятати три правила роботи switch у Swift:
- switch обирає першу відповідну гілку зверху вниз.
- Виконується рівно одна гілка. У Swift немає автоматичного переходу до наступної.
- default — це «якщо нічого не підійшло».
Саме тому switch так приємно читати: ви не очікуєте сюрпризів на кшталт «спрацювали два case підряд».
3. Вичерпність: чому switch змушує думати про «всі варіанти»
У Swift switch влаштований так, щоб ви не забували про випадки «а що, якщо прийде щось інше?». Спочатку це дратує («та відчепись, компіляторе!»), а потім рятує («дякую, компіляторе!»).
Термін вичерпність означає: switch зобовʼязаний покрити всі можливі варіанти значення. Якщо варіантів потенційно нескінченно багато (наприклад, Int), то без default ви просто фізично не перелічите все. Тому на числах і рядках default майже завжди потрібен.
Подивіться на приклад із командою користувача. Ми читаємо рядок, приводимо його до нижнього регістру і розгалужуємося:
import Foundation
let command = (readLine() ?? "").lowercased()
switch command {
case "help":
print("Доступні команди: help, version, exit") // Доступні команди: help, version, exit
case "version":
print("LibraryCLI v0.1") // LibraryCLI v0.1
case "exit":
print("Поки!") // Поки!
default:
print("Невідома команда: \(command)") // Невідома команда: ...
}
Тут default — це ваш страховий варіант. Причому не лише від неуважного користувача, а й від уважного, який втомився і випадково натиснув пробіл.
До речі, іноді вичерпність можна забезпечити і без default. Наприклад, для Bool у нас лише два значення: true і false. Отже, можна явно покрити обидва випадки:
import Foundation
let isAdmin = false
switch isAdmin {
case true:
print("Доступ: адміністратор") // (не виконається)
case false:
print("Доступ: користувач") // Доступ: користувач
}
Такий switch теж вичерпний: більше варіантів у Bool немає.
4. default: гілка «на все інше»
default потрібен часто, але він же — головне джерело лінощів і хаосу. Дуже легко зробити так: обробити один улюблений випадок, а все інше скинути в default без чіткої логіки. Це працює, але за тиждень ви самі не згадаєте, чому деякі випадки «не підтримуються».
Гарне правило для новачка таке: default має бути зрозумілим і безпечним. У простих CLI-програмах «зрозумілим і безпечним» зазвичай означає: вивести повідомлення, що команда невідома, і, можливо, підказати "help".
Приклад трохи дружелюбніший:
import Foundation
let command = (readLine() ?? "").lowercased()
switch command {
case "help":
print("Команди: help, exit") // Команди: help, exit
case "exit":
print("Завершення роботи...") // Завершення роботи...
default:
print("Не зрозумів команду. Введіть help.") // Не зрозумів команду. Введіть help.
}
Зверніть увагу: ми не намагаємося вгадати за користувача. Ми просто чесно кажемо, чого очікували.
Ще одна корисна дрібниця: обробляти порожній ввід як окремий випадок. Це робить UX кращим, а код — читабельнішим:
import Foundation
let command = (readLine() ?? "").lowercased()
switch command {
case "":
print("Порожній ввід. Введіть help.") // Порожній ввід. Введіть help.
case "help":
print("Команди: help, exit") // Команди: help, exit
case "exit":
print("Поки!") // Поки!
default:
print("Невідомо: \(command)") // Невідомо: ...
}
Технічно "" — це такий самий звичайний рядок, просто порожній.
5. Кілька значень в одному case
Дуже типовий сценарій: користувач вводить «так», але іноді пише "y", іноді "yes", іноді "т", а іноді взагалі CAPS LOCK вирішив, що він головний. Ми вже вміємо робити lowercased(), тож із великими літерами впораємося. Але все одно лишається кілька рівнозначних варіантів.
У switch можна перелічити кілька значень через кому — і це значно чистіше, ніж дублювати один і той самий print() у кількох гілках:
import Foundation
let answer = (readLine() ?? "").lowercased()
switch answer {
case "yes", "y", "так", "т":
print("Прийнято") // Прийнято
case "no", "n", "ні", "н":
print("Відхилено") // Відхилено
default:
print("Не зрозумів відповідь") // Не зрозумів відповідь
}
З точки зору читання це просто подарунок: «ось набір синонімів, робимо одне й те саме».
6. Порожня гілка: чому іноді потрібен break
Іноді вам потрібно явно сказати: «у цьому випадку нічого не робимо». Наприклад, ви обробляєте ввід числа і хочете не шуміти, якщо воно дорівнює нулю.
У Swift не можна залишати case зовсім порожнім. Але можна написати break, щоб гілка була синтаксично повноцінною, а ваш намір читався буквально як «нічого не робимо».
import Foundation
let x = 0
switch x {
case 0:
break
default:
print("x не дорівнює 0") // (не виконається)
}
Спочатку це виглядає трохи дивно, ніби ви зупиняєте switch. Але сенс простий: break тут означає «порожня дія».
7. Читабельність switch: порядок case і «плоска логіка»
switch сам по собі не гарантує красивого коду. Він лише дає інструмент. А ось як ви його використовуєте — це вже ваша відповідальність і, якщо чесно, ваш майбутній головний біль.
Найчастіша проблема — невдалий порядок гілок. Оскільки switch перевіряє case зверху вниз і бере перший збіг, логічно тримати такий стиль: спочатку найконкретніші варіанти, потім загальніші. Для default це правило майже завжди означає «ставимо default в кінці», бо інакше він перехопить усе, а інші гілки стануть недосяжними.
Ще один прийом читабельності — намагатися, щоб кожна гілка робила одну зрозумілу річ. Якщо всередині case починається «роман у трьох томах» із вкладених if, зазвичай це сигнал, що ви змішали кілька рівнів логіки. Поки ми не обговорюємо просунуті прийоми, але навіть на базовому рівні можна собі допомогти: виносити повідомлення користувачу в зрозумілі print(), а не будувати всередині одного case мініпроєкт.
Ось невелика таблиця, щоб візуально порівняти підходи:
| Ситуація | Частіше краще if/else | Частіше краще switch |
|---|---|---|
| Один-два варіанти, складні умови (&&, ||) | Так | Іноді, але не обовʼязково |
| Багато варіантів для одного значення (команда, оцінка, код) | Можна, але буде «сходинка» | Так, читається як меню |
| Потрібно «обробити все інше» | else | default |
8. Мініверсія застосунку: LibraryCLI і команди на switch
Зараз ми складемо цілісний фрагмент програми, який виглядатиме як справжній застосунок, а не як набір окремих прикладів. Ми поки не зберігаємо книги і не будуємо справжню базу — у нас ще немає масивів і словників. Але ми вже можемо зробити каркас: цикл вводу команд і розгалуження через switch.
Ось проста «оболонка»:
import Foundation
var isRunning = true
while isRunning {
print("Введіть команду (help/exit):", terminator: " ")
let command = (readLine() ?? "").lowercased()
switch command {
case "help":
print("Команди: help, exit") // Команди: help, exit
case "exit":
print("Завершення...") // Завершення...
isRunning = false
case "":
print("Порожня команда. Спробуйте help.") // Порожня команда. Спробуйте help.
default:
print("Невідома команда: \(command)") // Невідома команда: ...
}
}
Зверніть увагу на кілька речей.
По-перше, switch робить наш код «плоским». Нам не доводиться будувати драбину if/else if/else, і гілки виглядають як список команд.
По-друге, у нас є явна обробка порожнього вводу — це дрібниця, але вона робить застосунок дружелюбнішим.
По-третє, "exit" не просто друкує повідомлення, а змінює isRunning, щоб вийти з циклу: switch зручно поєднується з циклом.
І так, це саме той момент, коли починаєш поважати контроль потоку виконання. Ви буквально керуєте життям програми, як диспетчер в аеропорту, тільки без відповідальності за реальні літаки — поки що.
9. Типові помилки під час роботи зі switch
Помилка №1: очікувати, що switch виконає кілька гілок підряд.
Якщо ви прийшли в Swift із мов, де за замовчуванням є «провалювання» з case у case, то підсвідомо можете чекати, що після першого збігу виконається ще один блок. У Swift так не відбувається: виконується рівно одна гілка. Тому, якщо вам потрібно кілька дій для одного випадку, просто запишіть їх підряд усередині одного case.
Помилка №2: забути про default, коли варіантів нескінченно багато.
Для Int або String неможливо перелічити всі значення, тому default — це не «опція», а необхідність. Зазвичай це проявляється як помилка компіляції: switch must be exhaustive. Гарна реакція — не злитися, а додати акуратний default із зрозумілим повідомленням.
Помилка №3: ставити default не в кінці і випадково «перехопити все».
Іноді новачок намагається «спочатку обробити все інше», а потім дописати спеціальні команди нижче. Але switch іде зверху вниз, і якщо default стоїть рано, далі вже ніхто не дістанеться. Якщо ви бачите, що якісь case підсвічені як недосяжні, насамперед перевірте порядок.
Помилка №4: порівнювати «як у if» і намагатися писати умови замість шаблонів.
У switch не можна писати case command == "help": — це стиль if. У сьогоднішній лекції ми використовуємо лише прості значення в case. Пізніше switch стане ще потужнішим, але навіть зараз корисно памʼятати: case — це зіставлення з варіантом, а не довільна логіка.
Помилка №5: не нормалізувати ввід і потім дивуватися, що "Help" не працює.
Якщо ви порівнюєте рядки напряму, то "Help" і "help" — різні значення. Тому перед switch майже завжди варто зробити нормалізацію: хоча б lowercased(), а іноді й обробку порожніх рядків. Це не «костиль», а звичайна турбота про користувача, який не зобовʼязаний памʼятати ваш улюблений регістр.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ