Диапазоны и тернарный оператор
Детский билет в музей продают детям от 3 до 12 лет. Двенадцатилетний его получит: граница входит в отрезок. Магазин работает с 9:00 до 18:00, но в 18:00 двери уже закрыты: вторая граница — это момент, когда отрезок кончается.
Для каждого из двух случаев в Swift есть свой оператор. Оба создают диапазон — отрезок чисел от нижней границы до верхней.
Закрытый диапазон ...
Запись a...b включает обе границы, как детский билет:
let childAges = 3...12
print(childAges.contains(12)) // true
print(childAges.contains(13)) // falseРазберём по строкам:
3...12— все целые числа от 3 до 12, вместе с 12.containsпроверяет, попадает ли число в диапазон. Это действие умеет выполнять сам диапазон, и его вызывают через точку:childAges.contains(12)даётtrue.- Число 13 в диапазон не входит, и
contains(13)даётfalse.
Нижняя граница не может быть больше верхней. Запись 12...3 не даёт пустой диапазон, а аварийно завершает программу:
Fatal error: Range requires lowerBound <= upperBoundПолуоткрытый диапазон ..<
Запись a..<b останавливается перед b, как часы работы магазина:
let openHours = 9..<18
print(openHours.contains(9)) // true
print(openHours.contains(18)) // falseНижняя граница 9 входит в диапазон, а верхняя 18 — нет. Картинка с часами здесь неточна: в 9..<18 лежат только целые числа от 9 до 17, а у настоящего времени есть ещё и минуты.
Полуоткрытый диапазон удобен, когда верхняя граница означает конец или количество: в 0..<5 ровно пять чисел, от 0 до 4.
На собеседовании начинающего разработчика часто просят объяснить разницу между ... и ..<. Короткий ответ: первый включает верхнюю границу, второй останавливается перед ней.
Скобки вокруг диапазона
Чтобы вызвать contains прямо у записи диапазона, её берут в скобки: (1...5).contains(5). Без скобок Swift применит .contains к одному числу 5:
error: value of type 'Int' has no member 'contains'Тернарный оператор
Часто нужно выбрать одно из двух значений: детский билет или взрослый. Для этого есть тернарный оператор: условие ? a : b. Его название значит «из трёх частей»: условие и два значения.
let age = 7
let ticket = childAges.contains(age) ? "child" : "adult"
print(ticket) // childКак Swift выбирает значение:
- Сначала он вычисляет условие перед
?:childAges.contains(age)— этоtrue. - Условие верно, поэтому результатом становится значение между
?и:, строка"child". - Если бы условие было ложным, результатом стало бы значение после
:, строка"adult".
У тернарного оператора два правила:
- условие перед
?имеет типBool; - оба значения одного типа, иначе программа не скомпилируется.
Если смешать строку и число, например age > 5 ? "big" : 0, компилятор ответит так:
error: result values in '? :' expression have mismatching types 'String' and 'Int'Частая ошибка
Часы работы магазина записали закрытым диапазоном:
let hours = 9...18 // ✗
print(hours.contains(18)) // trueПрограмма считает магазин открытым в 18:00, хотя в это время он уже закрыт. Ошибки нет ни при компиляции, ни при запуске, есть только неверный ответ. Когда верхняя граница означает конец, нужен ..<, как в openHours выше.
Главное
a...bвключает обе границы:(3...12).contains(12)— этоtrue.a..<bостанавливается передb:(9..<18).contains(18)— этоfalse.containsпроверяет, попадает ли число в диапазон, а запись диапазона перед.containsберут в скобки.условие ? a : bдаётa, если условие верно, иb, если нет; оба значения одного типа.