Перейти к содержимому

Лекция 3. Операторы и управление потоком выполнения

В этой лекции разберём операторы Swift и конструкции управления потоком. Многие знакомы по Python, но Swift имеет существенные отличия и уникальные возможности: ??, guard, мощный switch с pattern matching, операторы диапазона.


1. Арифметические операторы

let a = 17, b = 5
print(a + b) // 22
print(a - b) // 12
print(a * b) // 85
print(a / b) // 3 (целочисленное деление для Int)
print(a % b) // 2 (остаток от деления)
ОперацияSwiftPython
Целочисленное деление/ для 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. Логические операторы

ОперацияSwiftPython
И&&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? = nil
let 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, 5
for i in 0..<5 { print(i) } // 0, 1, 2, 3, 4
SwiftPythonРезультат
1...5range(1, 6)1, 2, 3, 4, 5
0..<5range(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("Прохладно")
}
# Python
if 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 = 85
switch 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) }
// Аналог enumerate
for (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, 8
for i in stride(from: 0, through: 10, by: 2) { print(i) } // 0, 2, ..., 10
for i in stride(from: 10, through: 0, by: -2) { print(i) } // 10, 8, ..., 0
# Python
for i in range(0, 10, 2): print(i) # 0, 2, 4, 6, 8
for i in range(10, -1, -2): print(i) # 10, 8, ..., 0

9.2. Цикл while

var count = 5
while count > 0 {
print("Осталось: \(count)")
count -= 1
}

9.3. Цикл repeat-while

Тело выполняется хотя бы один раз, затем проверяется условие (аналог do-while в C):

var n = 1
repeat {
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("Три"); fallthrough
case 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 = False
for 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: break

13. Практический пример: 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

КонцепцияSwiftPython
И / ИЛИ / НЕ&& / || / !and / or / not
Тернарный операторa ? b : cb if a else c
Ветвлениеif / else if / elseif / elif / else
Оператор выбораswitch / casematch / case (3.10+)
Цикл forfor i in 1...5for i in range(1, 6)
Цикл do-whilerepeat { } whileнет (while True + break)
Null-coalescinga ?? ba if a is not None else b
Ранний выходguardнет (паттерн if + return)
Именованные циклыlabel: forнет

15. Упражнения

  1. Калькулятор. Два числа и оператор (+, -, *, /) — результат через switch. Обработайте деление на ноль.
  2. Валидатор пароля. Функция validatePassword(_ password: String?) -> Bool с guard: не nil, длина >= 8, есть цифра.
  3. Оценка. switch с диапазонами: 0–100 → «отлично» / «хорошо» / «удовл.» / «неуд.».
  4. Фибоначчи. Первые 20 чисел через while.
  5. Чётные. stride — чётные числа от 2 до 50.
  6. Поиск пары. Первая пара (i, j) из 1...20, где i * j == 200, через labeled break.

16. Вопросы для самопроверки

  1. Почему if count { } (где countInt) не скомпилируется?
  2. Что будет, если switch не покрывает все значения и нет default?
  3. Чем guard let отличается от if let по области видимости?
  4. Что делает fallthrough и когда его стоит избегать?
  5. Разница между stride(from:to:by:) и stride(from:through:by:)?
  6. Зачем нужны labeled statements?
  7. Чем repeat-while отличается от while?

Дополнительные материалы