Условия и ветвление

Программа становится живой, когда умеет принимать решения. В Swift для этого есть if/else, мощный switch и компактный тернарный оператор.
Суть урока: switch в Swift — это не просто замена цепочке if. Он умеет сопоставлять образцы, проверять диапазоны, требует покрыть все случаи и потому исключает забытые ветки.

Начнём с привычного if/else. Условие в Swift обязано быть типа Bool — нельзя написать if 1, как в некоторых языках:

let temperature = 28

if temperature > 30 {
    print("Жара")
} else if temperature > 20 {
    print("Тепло")
} else {
    print("Прохладно")
}

Когда вариантов много, на сцену выходит switch. В Swift он гораздо мощнее, чем в C: умеет сопоставлять диапазоны, кортежи, использовать условие where и обязан быть исчерпывающим — покрыть все возможные значения, иначе компилятор не пропустит код:

let score = 87

switch score {
case 90...100:
    print("Отлично")
case 70..<90:
    print("Хорошо")
case 50..<70:
    print("Удовлетворительно")
default:
    print("Нужно подтянуть")
}

Здесь 90...100 — замкнутый диапазон (включая 100), а 70..<90 — полузамкнутый (до 90, не включая). Ветка default ловит всё остальное и делает switch исчерпывающим. Можно добавить условие через where:

let point = (x: 2, y: 2)
switch point {
case let (x, y) where x == y:
    print("На диагонали")
case (let x, 0):
    print("На оси X в точке \(x)")
default:
    print("Где-то на плоскости")
}

Для простого выбора между двумя значениями есть тернарный оператор: условие ? a : b. Например, let label = isOn ? "Вкл" : "Выкл".

Попробуй сам ▶ — запусти код прямо в браузере (Pyodide). Здесь нет Swift, но логика та же, что под капотом мобильного кода:

# Имитируем switch со диапазонами через функцию-классификатор.
def grade(score):
    if 90 <= score <= 100:
        return 'Отлично'
    elif 70 <= score < 90:
        return 'Хорошо'
    elif 50 <= score < 70:
        return 'Удовлетворительно'
    else:
        return 'Нужно подтянуть'

for s in [95, 87, 61, 30]:
    print(s, '->', grade(s))

Как работает под капотом

Компилятор анализирует switch на исчерпывающность: для перечислений он проверит, что покрыты все случаи, и без default. Если хоть один случай пропущен, будет ошибка компиляции — именно это делает switch таким безопасным. Для числовых диапазонов компилятор генерирует эффективные сравнения, а сопоставление образцов разбирает кортежи и связывает переменные прямо в case.

Частые ошибки

  • Ожидать «провала» (fallthrough) как в C. В Swift case не проваливается в следующий автоматически; для этого есть отдельное ключевое слово fallthrough.
  • Неисчерпывающий switch. Без default или без покрытия всех случаев код не скомпилируется.
  • Перегружать тернарный оператор. Вложенные тернарники нечитаемы — лучше if/else.

Best practices

  • Для перечислений избегайте default — пусть компилятор напомнит про новый случай.
  • Используйте диапазоны (...,..<) вместо длинных цепочек сравнений.
  • Тернарный оператор — только для коротких, очевидных выборов.

Итоги. if/else подходит для простых развилок, switch — для исчерпывающего разбора множества случаев с сопоставлением образцов, а тернарный оператор — для коротких выборов. Исчерпывающий switch — мощный инструмент безопасности Swift.

Шире контекста

Исчерпывающий switch особенно засияет, когда мы дойдём до перечислений и моделирования состояний экрана. Представьте экран, который может быть в состоянии «загрузка», «успех» или «ошибка». Если вы разбираете эти случаи через switch без default, то в день, когда добавите четвёртое состояние «пусто», компилятор сам подсветит каждое место, где его забыли обработать. Это превращает рефакторинг из источника багов в управляемый процесс: компилятор работает вашим чек-листом. Поэтому опытные разработчики намеренно избегают default для собственных перечислений — они хотят, чтобы язык напоминал о незакрытых случаях. if/else остаётся уместным для простых бинарных развилок, но как только вариантов становится больше двух и каждый требует своей логики, switch с сопоставлением образцов делает код и короче, и безопаснее.

Проверьте себя
1. Что означает требование «исчерпывающего» switch в Swift?
ASwitch должен содержать ровно один case
BВсе возможные значения должны быть покрыты, иначе ошибка компиляции
CSwitch обязан заканчиваться break
DМожно использовать только с числами
2. Чем отличается диапазон 70..<90 от 70...90?
AНичем
BПервый не включает 90, второй включает
CПервый только для Double
DВторой работает быстрее