$ sudo teach IT

Зачем нужно ветвление

Программа редко идёт по одному прямому пути. Чаще нужно принять решение: показать одно сообщение или другое, разрешить действие или отказать, выбрать один вариант расчёта вместо другого. За это в Swift отвечает конструкция if — она проверяет условие и в зависимости от результата выполняет тот или иной блок кода.

if, else if и else

Базовая форма выглядит так: после if идёт условие, а в фигурных скобках — код, который выполнится, если условие истинно. Необязательный else добавляет блок «на все остальные случаи», а else if позволяет проверить ещё одно условие, если предыдущее оказалось ложным.

let temperature = 18

if temperature < 0 {
    print("Мороз, одевайтесь теплее")
} else if temperature < 15 {
    print("Прохладно, возьмите куртку")
} else {
    print("Тепло")
}

Swift проверяет условия по порядку сверху вниз и выполняет код только у первого блока, где условие оказалось true. Как только такой блок найден, до остальных else if и else дело не доходит.

Фигурные скобки — не опция, а правило

В языках вроде C или JavaScript для тела if из одной строки можно не писать фигурные скобки. В Swift так нельзя: скобки обязательны всегда, даже если внутри одна-единственная инструкция.

if temperature < 0 {
    print("Заморозки")
}

Это не прихоть создателей языка, а защита от реальной ошибки. В языках без обязательных скобок легко добавить вторую строку к телу условия и не заметить, что она на самом деле выполняется всегда, а не только при истинном условии — отступы обманывают глаз, а компилятор молчит. В Swift такая ошибка попросту не соберётся: компилятор потребует скобки, если строк больше одной, и не даст коду выглядеть не так, как он работает.

Условие обязано быть Bool

Ещё одно отличие от C и JavaScript: в Swift нет понятия «истинного» или «ложного» числа. Условие после if должно быть выражением типа Bool — и никаким другим. Нельзя написать if count, надеясь, что ноль будет означать «ложь», а любое другое число — «истину». Нужно явно сравнить: if count != 0.

Требование выглядит строже, чем в других языках, но избавляет от целого класса ошибок: код читается однозначно, а опечатка вроде случайно оставленной переменной вместо сравнения не проходит незамеченной — компилятор просто откажется собирать программу.

Сложные условия: && и ||

Часто одного простого сравнения недостаточно. Оператор && («и») требует, чтобы истинными были оба условия сразу, а || («или») — чтобы истинным было хотя бы одно.

let heightCm = 130
let age = 9
let hasAdult = true

let canRide = (heightCm >= 120 && age >= 10) || (heightCm >= 100 && hasAdult)
print(canRide)

Здесь прокатиться можно либо при достаточном росте и возрасте, либо при меньшем росте, но в сопровождении взрослого. Скобки группируют условия так же, как в математике, и делают порядок проверки явным. Обратите внимание: Swift вычисляет && и || слева направо и останавливается, как только результат уже понятен — если левая часть && ложна, правая даже не проверяется.

Вложенные if: когда пора остановиться

Условие внутри условия — это нормально и иногда нужно.

if hasAdult {
    if heightCm >= 100 {
        print("Можно кататься")
    } else {
        print("Слишком маленький рост")
    }
} else {
    print("Нужен взрослый рядом")
}

Но как только вложенность превышает два уровня, код становится трудно читать: приходится держать в голове сразу несколько условий, чтобы понять, какая ветка вообще выполнится. Это верный сигнал переписать логику — объединить условия через && и || в одно выражение или вынести часть проверки в отдельную функцию. Пример выше можно было бы сжать в одно составное условие, как в примере с canRide из прошлого раздела.

Тернарный оператор

Когда всё, что нужно, — выбрать одно из двух значений в зависимости от условия, полноценный if с присваиванием в каждой ветке выглядит громоздко. Для этого случая есть тернарный оператор: условие ? значение_если_true : значение_если_false.

let age = 20
let category = age >= 18 ? "взрослый" : "ребёнок"
print(category)

Это ровно то же самое, что if age >= 18 { category = "взрослый" } else { category = "ребёнок" }, только в одну строку. Тернарный оператор читается лучше if, когда выбор простой и обе части короткие — как в примере выше. Но если внутри тернарного оператора появляется ещё один тернарный оператор или сложное выражение, читаемость резко падает: такую запись приходится буквально дешифровать взглядом. В этом случае обычный if / else или отдельная переменная с пояснением будут понятнее.

if как выражение

Начиная со Swift 5.9, if можно использовать не только как инструкцию, но и как выражение, которое сразу возвращает значение:

let mark = 7
let grade = if mark >= 8 {
    "отлично"
} else if mark >= 5 {
    "хорошо"
} else {
    "нужно подтянуть"
}
print(grade)

Все ветки должны возвращать значение одного типа, а else становится обязательным — иначе непонятно, что вернуть, если ни одно условие не подошло. Такая запись короче классического варианта с промежуточной переменной и присваиванием в каждой ветке, но встречается в реальном коде заметно реже: большинство Swift-разработчиков по привычке пишут обычный if с присваиванием, и в чужом коде вы будете видеть в основном его.

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

  • Ожидать, что фигурные скобки можно опустить для однострочного тела if, как в JavaScript, — в Swift это ошибка компиляции.
  • Пытаться использовать число или строку как условие напрямую (if count) вместо явного сравнения (if count != 0).
  • Путать оператор сравнения == с оператором присваивания = в условии — Swift не даст скомпилировать такой код, но текст ошибки иногда сбивает с толку.
  • Городить тернарный оператор внутри тернарного оператора вместо того, чтобы вернуться к обычному if / else.
  • Наращивать вложенность if вместо того, чтобы объединить условия через && и ||.

Итоги

  • if, else if и else проверяются по порядку, выполняется первая подошедшая ветка.
  • Фигурные скобки обязательны всегда, даже для одной строки — это защищает от скрытых ошибок отступов.
  • Условие обязано быть выражением типа Bool, автоматического приведения чисел и строк нет.
  • && и || объединяют несколько условий в одно; вложенность if глубже двух уровней — повод переписать код.
  • Тернарный оператор условие ? a : b хорош для простого выбора значения и вреден при вложенности.
  • if как выражение (Swift 5.9) — компактная альтернатива, но классическая форма встречается в коде чаще.

Проверьте себя

3 вопроса

Совет по погоде

Напишите функцию weatherAdvice, которая по температуре воздуха в градусах (Int) возвращает совет об одежде.

Правила ровно такие:

  • температура меньше 0 — вернуть строку "Наденьте зимнюю куртку";
  • температура от 0 до 14 включительно — вернуть "Возьмите куртку потеплее";
  • температура от 15 до 24 включительно — вернуть "Хватит лёгкой кофты";
  • температура 25 и выше — вернуть "Наденьте футболку".

Используйте if, else if и else.

Правила аттракциона

В парке аттракционов есть правило безопасности для одной карусели. Напишите функцию canRide(age:heightCm:hasAdult:), которая возвращает true, если кататься можно, и false — если нельзя.

Кататься разрешено, если выполняется хотя бы одно из условий:

  • рост не меньше 120 см и возраст не меньше 10 лет;
  • рост не меньше 100 см и рядом есть взрослый (hasAdult == true).

Во всех остальных случаях — false.

Приветствие пользователя

Напишите функцию greetUser(_:), которая принимает необязательное имя пользователя (String?) и возвращает строку приветствия.

Правила:

  • если имя отсутствует (nil) или это пустая строка — вернуть "Привет, гость!";
  • если имя есть и в нём не больше 12 символов — вернуть "Привет, ИМЯ!", подставив имя;
  • если имя есть и в нём больше 12 символов — вернуть "Добро пожаловать, уважаемый ИМЯ!".

Используйте разворачивание опционала (например, if let) вместе с проверкой длины строки.