1. Тип Bool: «так» і «ні» як звичайний тип
Якщо ви тільки починаєте програмувати, легко подумати так: «Ну, я ж можу написати 1 для „так“ і 0 для „ні“.» Деякі мови це навіть дозволяють. Swift — ні. І, чесно кажучи, він має рацію: «так» і «ні» — це окремий зміст, окрема категорія даних, тож для неї є окремий тип.
Bool — це тип, у якого є лише два можливі значення: true (істина) і false (хиба). Він потрібен, щоб зберігати результат перевірок: «число більше за нуль?», «команда дорівнює exit?», «рік у допустимому діапазоні?». Завдяки такому типу код стає читабельнішим: вам не потрібно тримати в голові, що 1 — це „так“, а 0 — „ні“. Ви бачите це безпосередньо в значенні.
Уявіть, що Bool — це вимикач. Він або увімкнений (true), або вимкнений (false). Сьогодні ми вчимося робити такі «вимикачі» з чисел і рядків.
true і false: оголошуємо булеві значення й виводимо їх
Спочатку — найпростіша річ: булеві значення можна записати вручну. Це корисно для тестів і для того, щоб звикнути до типу. Так, у реальному житті ви частіше отримуватимете Bool із порівнянь, але починати краще з того, що можна побачити без магії.
let isSwiftFun: Bool = true
let isDebugMode: Bool = false
print("isSwiftFun = \(isSwiftFun)") // isSwiftFun = true
print("isDebugMode = \(isDebugMode)") // isDebugMode = false
Тут важливо одразу звикнути до двох речей. По-перше, Bool — звичайний тип: його можна писати явно (: Bool), а можна дати Swift вивести його автоматично. По-друге, Bool чудово виводиться через інтерполяцію в рядок — ми вже вміємо це робити.
І без явного типу можна — так буде навіть простіше:
let isLoggedIn = true
let hasPremium = false
print(isLoggedIn) // true
print(hasPremium) // false
Поки що все виглядає надто просто, майже підозріло. Спокійно: справжня цінність Bool починається там, де ми його обчислюємо, а не пишемо вручну.
2. Порівняння чисел: отримуємо Bool з Int
Порівняння — головний спосіб отримати Bool. Ми беремо два значення, найчастіше числа, і питаємо: «вони рівні?», «одне більше за інше?», «чи не менше?». Відповідь завжди булева: або так, або ні.
Оператори порівняння порядку: <, >, <=, >=
Ці оператори відповідають на запитання «хто більший, а хто менший». Для цілих чисел (Int) вони працюють так, як і очікується.
Для орієнтиру — коротка таблиця, щоб мозок не вдавав, ніби й так усе пам’ятає:
| Оператор | Читається як | Приклад | Результат |
|---|---|---|---|
|
менше | |
|
|
більше | |
|
|
менше або дорівнює | |
|
|
більше або дорівнює | |
|
Мініприклад:
let a = 10
let b = 5
let isGreater = a > b
let isNotLess = a >= b
print("isGreater = \(isGreater)") // isGreater = true
print("isNotLess = \(isNotLess)") // isNotLess = true
Зверніть увагу: вираз a > b — це не команда, а значення. Його обчислюють, і в результаті отримуємо Bool. Ми можемо зберегти його в змінну, вивести, передати далі — наприклад, у наступній лекції в if.
Перевірка діапазону без діапазонів
У майбутньому ми обговоримо зручніші способи, але вже зараз можемо перевірити, чи число «всередині» певного інтервалу, двома порівняннями:
let x = 7
let isInRange = x >= 1 && x <= 10
print(isInRange) // true
Стоп. Тут зʼявився && — логічний оператор «і». За планом ми детально розглянемо його в наступній лекції про логічні операції, але саму ідею вже видно: часто одного порівняння замало, тож другу частину умови просто додають. Якщо вам поки що не хочеться думати про &&, не думайте. У цій лекції ми зосереджуємося саме на тому, що порівняння дає Bool.
3. Рівність і нерівність: == і !=
Якщо порівняння порядку відповідає на питання «хто більший», то рівність відповідає на питання «чи однакові значення». І це настільки часта операція, що трапляється всюди: від перевірки команди до порівняння результатів обчислень.
== — це «дорівнює», а != — це «не дорівнює»
Приклад із числами:
let n = 7
let isSeven = n == 7
let isNotSeven = n != 7
print("isSeven = \(isSeven)") // isSeven = true
print("isNotSeven = \(isNotSeven)") // isNotSeven = false
== — це оператор перевірки на рівність, і він повертає Bool.
Порівняння рядків: String теж можна порівнювати на рівність
Із рядками нас найчастіше цікавить саме рівність або нерівність: чи ввів користувач слово exit, чи збігається пароль, чи дорівнює команда help.
let command = "exit"
let isExit = command == "exit"
print(isExit) // true
І важливий нюанс: порівняння рядків чутливе до регістру й пробілів.
let command = "Exit"
print(command == "exit") // false
Поки ми не вивчали «нормалізацію введення» — обрізання пробілів, lowercased() тощо, — тому просто фіксуємо факт: рядок порівнюється буквально.
4. Найчастіша ситуація: порівнюємо те, що ввів користувач
На практиці порівняння рідко виконують над «ідеальними» константами. Зазвичай дані надходять від користувача, а користувач — істота творча. Сьогодні зберемо акуратний мінішаблон: «введення → перетворення до потрібного типу → порівняння».
readLine() повертає String?, отже спочатку робимо String
Якщо порівнюємо рядок, спочатку отримаємо звичайний рядок через ??.
let input = readLine() ?? ""
let isEmpty = input == ""
print("input = '\(input)'") // наприклад: input = 'hello'
print("isEmpty = \(isEmpty)") // наприклад: isEmpty = false
Тут ми не робимо жодних розгалужень, а просто друкуємо результат. Але сенс уже корисний: ми отримали булевий «датчик» isEmpty.
Якщо хочемо порівнювати як число — зʼявляються два джерела проблем
Коли читаємо число з консолі, можуть трапитися дві неприємності.
- Перша: readLine() повернув nil — наприклад, введення завершилося.
- Друга: рядок є, але це не число ("abc").
Тому в базових задачах зручно робити ось так:
let text = readLine() ?? ""
let n = Int(text) ?? 0
let isEven = n % 2 == 0
print("n = \(n), isEven = \(isEven)") // наприклад: n = 12, isEven = true
Тут n % 2 дає остачу від ділення на 2, а порівняння == 0 перетворює це на Bool. Виходить акуратний факт: «число парне?».
Так, 0 як значення за замовчуванням — суперечливе рішення, бо користувач міг ввести сміття, а ми тихо вдаємо, що він ввів нуль. На ранньому етапі навчання це допустимо: ми тренуємо механіку типів. Пізніше ми навчимося чесніше обробляти помилки й Optional.
5. Акуратні умови
Порівняння легко перетворити на кашу. Не тому, що Swift поганий, а тому, що ми люди й іноді пишемо код так, ніби поспішаємо на останній автобус. Є кілька простих правил, які на диво швидко підвищують читабельність.
Булеві змінні мають читатися як запитання
Якщо змінна зберігає Bool, її ім’я має звучати так, ніби ви ставите запитання. Тоді код читається майже як текст.
Порівняйте:
let age = 20
let flag = age >= 18
print(flag) // true
і
let age = 20
let isAdult = age >= 18
print(isAdult) // true
У другому випадку голова взагалі не напружується: «isAdult» — це запитання «дорослий?». Це особливо важливо, коли далі ви будете писати if isAdult { ... } і читати це як речення.
Розділяйте «обчислення» й «повідомлення»
Початківці часто намагаються втиснути все в один рядок. Коротко — так. Зрозуміло — не завжди. Краще спочатку порахувати, а потім вивести.
let a = 10
let b = 3
let isDivisible = a % b == 0
print("a ділиться на b: \(isDivisible)") // a ділиться на b: false
У таких прикладах ви тренуєте правильну звичку: вираз порівняння дає Bool, Bool можна зберігати, друкувати й пізніше використовувати як умову.
6. Приклад: заготовка під консольний застосунок
Щоб приклади не були набором випадкових чисел, давайте уявимо найпростіший консольний застосунок, який ми поступово будемо «оживляти» в міру курсу. Назвемо його LibraryMini: поки він нічого не «робить», але вже читає введення й обчислює ознаки.
Сценарій такий: користувач вводить команду й рік видання. Ми ще не розгалужуємося — поки що не можна, — але обчислюємо ключові ознаки й друкуємо їх.
let command = readLine() ?? ""
let yearText = readLine() ?? ""
let year = Int(yearText) ?? 0
let isExitCommand = command == "exit"
let isYearPositive = year > 0
let isModern = year >= 2000
print("isExitCommand = \(isExitCommand)") // наприклад: true
print("isYearPositive = \(isYearPositive)")
print("isModern = \(isModern)")
Чому це корисно, хоча «нічого не відбувається»? Тому що це правильне архітектурне мислення: спочатку ми перетворюємо введення на зрозумілі факти (Bool), а вже потім вирішуємо, що робити. У наступній лекції ми саме так і вчинимо: візьмемо ці булеві змінні й почнемо розгалуження.
7. Типові помилки під час роботи з Bool і порівняннями
Помилка №1: плутати = і ==.
= — це присвоєння: «покладіть значення в змінну». == — це порівняння: «чи рівні два значення?»; результатом буде Bool. Плутанина здається кумедною, доки компілятор вас рятує. Але якщо ви звикнете мислити правильно вже зараз, далі буде значно менше болю.
Помилка №2: намагатися використовувати число як умову замість Bool.
У деяких мовах 0 — це false, а 1 — це true. У Swift так не можна: умова має бути булевим виразом. Тому замість «магічних» нулів і одиниць ми пишемо явні порівняння на кшталт n > 0 або n == 1. Це трохи довше, зате читабельніше й без прихованих правил. Саме такий стиль булевих перевірок є базовим для if/guard, наприклад у прикладах на кшталт guard x == 0, ....
Помилка №3: порівнювати різні типи «на око».
Дуже часто намагаються порівняти Int із рядком, бо «в рядку ж написано число». Але для Swift це різні типи, і він не вгадуватиме ваші наміри. Правильний шлях — перетворити введення на потрібний тип: let n = Int(text) ?? 0, і лише потім порівнювати.
Помилка №4: порівнювати readLine() напряму, забувши про String?.
readLine() повертає String?, тобто значення може бути відсутнє. Тому звичка «спочатку нормалізуємо» через ?? "" — це не занудство, а страховка від зайвих проблем. І лише після цього порівнюємо рядок із рядком.
Помилка №5: давати булевим змінним імена на кшталт flag, tmp, b1.
Такі назви швидко перетворюють код на ребус: «flag чого саме?». Набагато краще одразу звикати до is…, has…, can…: isExitCommand, hasTicket, canEnter. Тоді навіть без if код уже читається як людський текст, і в наступній лекції перехід до розгалужень буде максимально природним.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ