Лекция 3. Операторы и управление потоком выполнения
В этой лекции разберём операторы Swift и конструкции управления потоком. Многие знакомы по Python, но Swift имеет существенные отличия и уникальные возможности: ??, guard, мощный switch с pattern matching, операторы диапазона.
1. Арифметические операторы
let a = 17, b = 5print(a + b) // 22print(a - b) // 12print(a * b) // 85print(a / b) // 3 (целочисленное деление для Int)print(a % b) // 2 (остаток от деления)| Операция | Swift | Python |
|---|---|---|
| Целочисленное деление | / для Int | // |
| Обычное деление | / для Double | / |
| Остаток | % | % |
| Степень | нет оператора (pow()) | ** |
В Swift / между целыми всегда возвращает целое. Для дробного результата нужен Double:
let x = Double(17) / Double(5) // 3.4Важно: Swift не допускает неявного смешивания типов.
17 / 5.0не скомпилируется.
Составные операторы: +=, -=, *=, /=, %=. Операторов ++ и -- в Swift нет — используйте += 1.
2. Операторы сравнения
Возвращают Bool. Синтаксис как в Python: ==, !=, <, >, <=, >=.
Отличие: в Swift нельзя составлять цепочки. Вместо 1 < x < 100 (Python) пишем x > 1 && x < 100.
3. Логические операторы
| Операция | Swift | Python |
|---|---|---|
| И | && | and |
| ИЛИ | || | or |
| НЕ | ! | not |
let isAdult = true, hasTicket = false
if isAdult && hasTicket { print("Проход разрешён")} else if isAdult || hasTicket { print("Частичный доступ")}
if !hasTicket { print("Билета нет") }Как и в Python, вычисление ленивое (short-circuit).
4. Оператор объединения по nil: ??
Если Optional содержит значение — используется оно; если nil — берётся значение справа.
let username: String? = nillet displayName = username ?? "Гость" // "Гость"# Python (аналог)display_name = username if username is not None else "Гость"Можно выстраивать цепочку: primary ?? secondary ?? fallback. Подробнее об Optionals — в Лекции 6.
5. Операторы диапазона
Закрытый a...b — включает обе границы. Полуоткрытый a..<b — не включает b.
for i in 1...5 { print(i) } // 1, 2, 3, 4, 5for i in 0..<5 { print(i) } // 0, 1, 2, 3, 4| Swift | Python | Результат |
|---|---|---|
1...5 | range(1, 6) | 1, 2, 3, 4, 5 |
0..<5 | range(5) | 0, 1, 2, 3, 4 |
Односторонние диапазоны:
let names = ["Анна", "Борис", "Виктор", "Галина"]print(names[2...]) // ["Виктор", "Галина"]print(names[..<2]) // ["Анна", "Борис"]6. Условные конструкции: if, else, else if
Два правила Swift: скобки вокруг условия не обязательны (и обычно не ставятся), а фигурные скобки {} обязательны всегда.
let temperature = 25
if temperature > 30 { print("Жарко")} else if temperature > 20 { print("Тепло")} else { print("Прохладно")}# Pythonif temperature > 30: print("Жарко")elif temperature > 20: print("Тепло")else: print("Прохладно")Важно: условие должно быть типа
Bool. Нельзяif count { }— нужноif count != 0 { }. В Python любое значение truthy/falsy — в Swift такого нет.
7. Тернарный оператор
let status = age >= 18 ? "совершеннолетний" : "несовершеннолетний"# Python — другой порядокstatus = "совершеннолетний" if age >= 18 else "несовершеннолетний"В Swift условие перед значениями, в Python — между.
8. Оператор switch
Один из самых мощных инструментов Swift — значительно мощнее switch из C/Java, ближе к match/case Python 3.10+.
let direction = "north"
switch direction {case "north": print("Север")case "south": print("Юг")case "east", "west": print("Восток или Запад")default: print("Неизвестно")}Ключевые особенности:
- Исчерпываемость — компилятор требует покрыть все варианты или добавить
default. - Нет неявного проваливания —
breakпослеcaseне нужен.
Диапазоны в case
let score = 85switch score {case 90...100: print("Отлично")case 75..<90: print("Хорошо")case 60..<75: print("Удовл.")case 0..<60: print("Неуд.")default: print("Ошибка")}Кортежи и привязка значений
let point = (2, 0)switch point {case (0, 0): print("Начало координат")case (let x, 0): print("На оси X, x = \(x)")case (0, let y): print("На оси Y, y = \(y)")case (let x, let y): print("Точка (\(x), \(y))")}// "На оси X, x = 2"Условие where
switch (3, 3) {case let (x, y) where x == y: print("На диагонали")case let (x, y): print("Точка (\(x), \(y))")}Сравнение с Python
# Python 3.10+match point: case (0, 0): print("Начало координат") case (x, 0): print(f"На оси X, x = {x}") case (x, y): print(f"Точка ({x}, {y})")Swift switch требует default, использует let для привязки и поддерживает where.
9. Циклы
9.1. Цикл for-in
for i in 1...5 { print(i) }
let fruits = ["яблоко", "банан", "вишня"]for fruit in fruits { print(fruit) }
// Аналог enumeratefor (i, fruit) in fruits.enumerated() { print("\(i): \(fruit)")}
// Словарьlet caps = ["Россия": "Москва", "Франция": "Париж"]for (country, capital) in caps { print("\(country) — \(capital)") }
// Игнорирование переменнойfor _ in 1...3 { print("Повтор") }Функция stride — аналог range с шагом
for i in stride(from: 0, to: 10, by: 2) { print(i) } // 0, 2, 4, 6, 8for i in stride(from: 0, through: 10, by: 2) { print(i) } // 0, 2, ..., 10for i in stride(from: 10, through: 0, by: -2) { print(i) } // 10, 8, ..., 0# Pythonfor i in range(0, 10, 2): print(i) # 0, 2, 4, 6, 8for i in range(10, -1, -2): print(i) # 10, 8, ..., 09.2. Цикл while
var count = 5while count > 0 { print("Осталось: \(count)") count -= 1}9.3. Цикл repeat-while
Тело выполняется хотя бы один раз, затем проверяется условие (аналог do-while в C):
var n = 1repeat { print(n); n *= 2} while n < 100В Python прямого аналога нет — используют
while Trueсbreak.
10. Управляющие операторы: break, continue, fallthrough
break — выход из цикла или switch:
for i in 1...100 { if i == 5 { break } print(i) // 1, 2, 3, 4}continue — пропуск итерации:
for i in 1...10 { if i % 2 == 0 { continue } print(i) // 1, 3, 5, 7, 9}fallthrough — принудительное проваливание в следующий case (без проверки условия):
switch 3 {case 3: print("Три"); fallthroughcase 4: print("Три или четыре")default: print("Другое")}// Три// Три или четыре
fallthroughиспользуется редко — обычно лучше перечислить значения через запятую.
11. Оператор guard — ранний выход
guard отсеивает невалидные случаи, позволяя далее работать с «чистыми» данными.
func greet(name: String?) { guard let name = name else { print("Имя не указано"); return } print("Привет, \(name)!") // name доступна здесь}Отличие от if let: переменная из guard let доступна после блока (а не только внутри), а блок else обязателен и должен содержать выход (return, break, throw).
Пример: валидация
func processAge(input: String?) { guard let input = input else { print("Нет ввода"); return } guard let age = Int(input) else { print("Не число"); return } guard age >= 0 && age <= 150 else { print("Вне диапазона"); return } print("Возраст: \(age)")}# Python — аналогичный паттернdef process_age(s): if s is None: print("Нет ввода"); return try: age = int(s) except ValueError: print("Не число"); return if not (0 <= age <= 150): print("Вне диапазона"); return print(f"Возраст: {age}")12. Именованные инструкции (Labeled Statements)
Метки указывают, к какому циклу относится break или continue во вложенных конструкциях.
search: for i in 1...10 { for j in 1...10 { if i * j == 50 { print("Найдено: \(i) × \(j) = 50") break search // Выход из ОБОИХ циклов } }}В Python именованных циклов нет — приходится использовать флаги:
found = Falsefor i in range(1, 11): for j in range(1, 11): if i * j == 50: print(f"{i} × {j} = 50"); found = True; break if found: break13. Практический пример: FizzBuzz
for i in 1...30 { switch (i % 3, i % 5) { case (0, 0): print("FizzBuzz") case (0, _): print("Fizz") case (_, 0): print("Buzz") default: print(i) }}14. Сводная таблица: Swift vs Python
| Концепция | Swift | Python |
|---|---|---|
| И / ИЛИ / НЕ | && / || / ! | and / or / not |
| Тернарный оператор | a ? b : c | b if a else c |
| Ветвление | if / else if / else | if / elif / else |
| Оператор выбора | switch / case | match / case (3.10+) |
| Цикл for | for i in 1...5 | for i in range(1, 6) |
| Цикл do-while | repeat { } while | нет (while True + break) |
| Null-coalescing | a ?? b | a if a is not None else b |
| Ранний выход | guard | нет (паттерн if + return) |
| Именованные циклы | label: for | нет |
15. Упражнения
- Калькулятор. Два числа и оператор (
+,-,*,/) — результат черезswitch. Обработайте деление на ноль. - Валидатор пароля. Функция
validatePassword(_ password: String?) -> Boolсguard: неnil, длина >= 8, есть цифра. - Оценка.
switchс диапазонами: 0–100 → «отлично» / «хорошо» / «удовл.» / «неуд.». - Фибоначчи. Первые 20 чисел через
while. - Чётные.
stride— чётные числа от 2 до 50. - Поиск пары. Первая пара
(i, j)из1...20, гдеi * j == 200, через labeledbreak.
16. Вопросы для самопроверки
- Почему
if count { }(гдеcount—Int) не скомпилируется? - Что будет, если
switchне покрывает все значения и нетdefault? - Чем
guard letотличается отif letпо области видимости? - Что делает
fallthroughи когда его стоит избегать? - Разница между
stride(from:to:by:)иstride(from:through:by:)? - Зачем нужны labeled statements?
- Чем
repeat-whileотличается отwhile?