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

Упражнения из лекций


Лекция 1. Введение в Swift и его экосистему

  1. Установка и проверка. Установите Swift на свою систему Linux. Выполните команду swift --version и убедитесь, что вывод содержит номер версии Swift.

  2. Hello, World! Создайте файл hello.swift, в котором программа выводит "Hello, World!". Скомпилируйте его с помощью swiftc и запустите полученный бинарный файл.

  3. Визитная карточка. Напишите программу card.swift, которая объявляет константы с вашим именем, возрастом и городом, а затем выводит их в формате:

    Имя: Иван
    Возраст: 20
    Город: Москва

    Используйте интерполяцию строк (\(переменная)).

  4. Калькулятор. Напишите программу calc.swift, которая объявляет две целочисленные константы a и b, а затем выводит результаты сложения, вычитания, умножения и деления (целочисленного).

  5. REPL-эксперименты. Запустите Swift REPL (swift) и выполните следующее:

    • объявите константу типа String;
    • объявите переменную типа Int и измените её значение;
    • попробуйте присвоить строку целочисленной переменной и изучите сообщение об ошибке.
  6. Сравнение с Python. Напишите одну и ту же программу (вывод таблицы умножения для числа 7) на Python и на Swift. Сравните синтаксис и процесс запуска.


Лекция 2. Переменные, константы и базовые типы данных

Задание 1. Переменные и константы

Объявите значения, выбрав let или var:

  • Имя пользователя (не меняется)
  • Текущий счёт в игре (меняется)
  • Число Пи (не меняется)
  • Текущая дата в формате строки (меняется)

Скомпилируйте через swiftc и убедитесь, что программа работает.

Задание 2. Преобразование типов

Объявите a: Int = 17 и b: Double = 3.0. Вычислите результат деления a на b (тип Double) и выведите через строковую интерполяцию.

Задание 3. Работа со строками

Создайте строку с полным именем. Выведите: количество символов, первый и последний символ, строку в верхнем регистре, результат проверки contains("ван").

Задание 4. Кортежи

Напишите функцию minMax(array:), возвращающую кортеж (min: Int, max: Int):

func minMax(array: [Int]) -> (min: Int, max: Int) {
// ваш код
}
let result = minMax(array: [3, 1, 7, -2, 5])
print("Мин: \(result.min), макс: \(result.max)")
// Ожидаемо: Мин: -2, макс: 7

Задание 5. Type Alias

Создайте typealias Student = (name: String, age: Int, grade: Double). Напишите функцию, принимающую [Student] и возвращающую средний балл.


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

  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.

Лекция 4. Функции и замыкания

Упражнение 1. Напишите функцию power(base:exponent:), которая возводит число в степень. Значение exponent по умолчанию — 2.

print(power(base: 3)) // 9
print(power(base: 2, exponent: 10)) // 1024

Упражнение 2. Напишите функцию joinStrings, принимающую вариативный параметр строк и разделитель (по умолчанию ", "), возвращающую объединённую строку.

print(joinStrings("Swift", "Python", "Go")) // Swift, Python, Go
print(joinStrings("a", "b", "c", separator: " - ")) // a - b - c

Упражнение 3. Напишите функцию applyToEach, принимающую inout-массив [Int] и замыкание (Int) -> Int, применяющее преобразование к каждому элементу.

var nums = [1, 2, 3, 4, 5]
applyToEach(&nums) { $0 * $0 }
print(nums) // [1, 4, 9, 16, 25]

Упражнение 4. Напишите makeMultiplier(factor:), возвращающую замыкание, умножающее число на factor.

let triple = makeMultiplier(factor: 3)
print(triple(7)) // 21
print(triple(10)) // 30

Упражнение 5. Используя map, filter, reduce и trailing closure, обработайте массив 1…20: отберите числа, делящиеся на 3, возведите в квадрат, найдите сумму.


Лекция 5. Коллекции

Упражнение 1. Создайте массив целых чисел от 1 до 20. Используя filter и reduce, найдите сумму всех чисел, которые делятся на 3.

// Ожидаемый результат: 3 + 6 + 9 + 12 + 15 + 18 = 63

Упражнение 2. Дан массив строк — названия городов. Используя map и sorted, получите массив строк вида "ГОРОД (N букв)", отсортированный по длине названия.

let cities = ["Москва", "Уфа", "Новосибирск", "Казань", "Сочи"]
// Ожидаемый результат:
// ["УФА (3 букв)", "СОЧИ (4 букв)", "КАЗАНЬ (6 букв)", "МОСКВА (6 букв)", "НОВОСИБИРСК (11 букв)"]

Упражнение 3. Дано два множества Set<String> — навыки двух программистов. Найдите: (а) общие навыки, (б) уникальные навыки каждого, (в) все навыки вместе.

let dev1: Set = ["Swift", "Python", "Git", "SQL", "Docker"]
let dev2: Set = ["Python", "JavaScript", "Git", "React", "Docker"]

Упражнение 4. Создайте словарь [String: [Int]], где ключ — имя студента, значение — массив оценок. Используя map и reduce, создайте новый словарь [String: Double] со средними оценками.

let grades = [
"Анна": [90, 85, 92, 88],
"Борис": [70, 65, 80, 75],
"Виктор": [95, 100, 92, 98]
]
// Ожидаемый результат: ["Анна": 88.75, "Борис": 72.5, "Виктор": 96.25]

Упражнение 5. Дан массив опциональных строк. Используя compactMap, извлеките непустые значения и преобразуйте их в верхний регистр.

let input: [String?] = ["swift", nil, "python", nil, "go", nil]
// Ожидаемый результат: ["SWIFT", "PYTHON", "GO"]

Упражнение 6. Напишите цепочку функциональных вызовов, которая из строки текста извлекает все слова длиной больше 4 символов, убирает дубликаты и возвращает отсортированный массив в нижнем регистре.

let text = "Swift это Swift язык для разработки приложений для Apple и Linux"
// Ожидаемый результат: ["apple", "linux", "swift", "разработки", "приложений"]

Лекция 6. Optionals — безопасная работа с отсутствием значений

Упражнение 1. Напишите функцию safeDivide(_ a: Double, _ b: Double) -> Double?, возвращающую результат деления или nil при делении на ноль.

print(safeDivide(10, 3) as Any) // Optional(3.3333...)
print(safeDivide(10, 0) as Any) // nil

Упражнение 2. Напишите функцию firstPositive(_ numbers: [Int]) -> Int?, возвращающую первое положительное число или nil.

print(firstPositive([-3, -1, 0, 4, 7]) as Any) // Optional(4)
print(firstPositive([-3, -1, 0]) as Any) // nil

Упражнение 3. Дан словарь [String: String] с данными пользователя. Напишите функцию greetUser, которая с помощью guard let извлекает "name" и "age" (преобразуя в Int), и выводит приветствие или сообщение об ошибке.

greetUser(["name": "Олег", "age": "22"]) // Привет, Олег! Тебе 22 лет.
greetUser(["name": "Анна"]) // Ошибка: неполные данные

Упражнение 4. С помощью compactMap преобразуйте массив строк в [Double], затем найдите среднее через reduce.

let data = ["3.14", "abc", "2.71", "", "1.0"]
// Ожидаемый результат: среднее ≈ 2.283

Упражнение 5. Создайте структуры Company, Department, Employee с опциональными вложенными свойствами. Используя optional chaining и ??, безопасно получите имя сотрудника.


Лекция 7. Структуры и классы

Упражнение 1. Создайте структуру Temperature с хранимым свойством celsius: Double и вычисляемым свойством fahrenheitget и set). Формула: F = C × 9/5 + 32.

var temp = Temperature(celsius: 100)
print(temp.fahrenheit) // 212.0
temp.fahrenheit = 32
print(temp.celsius) // 0.0

Упражнение 2. Создайте структуру Vector2D с x, y: Double. Добавьте: вычисляемое свойство magnitude, mutating func scale(by:), статический метод static func add(_:_:) -> Vector2D.

Упражнение 3. Создайте класс Animal со свойствами name и sound. Присвойте один объект другому, измените свойство — убедитесь, что изменение отразилось на обоих. Повторите с аналогичной структурой и сравните.

Упражнение 4. Создайте структуру StepCounter со свойством totalSteps: Int с didSet, выводящим "Шагов добавлено: X. Всего: Y.".

var stepper = StepCounter(totalSteps: 0)
stepper.totalSteps = 100 // Шагов добавлено: 100. Всего: 100.
stepper.totalSteps = 360 // Шагов добавлено: 260. Всего: 360.

Упражнение 5. Создайте класс LinkedNode с var value: Int и var next: LinkedNode?. Постройте цепочку из трёх узлов и пройдите по ней. Объясните, почему для связного списка необходим class, а не struct.


Лекция 8. Наследование и полиморфизм

Упражнение 1. Создайте иерархию Transport -> Car -> ElectricCar. Каждый класс переопределяет describe(). ElectricCar добавляет batteryLevel: Int.

Упражнение 2. Создайте BankAccount с designated и convenience инициализаторами. Дочерний SavingsAccount добавляет interestRate и метод addInterest().

Упражнение 3. Создайте массив фигур (Circle, Rectangle, Triangle). Используя is и as?, посчитайте количество каждого типа и выведите площади.

Упражнение 4. Создайте Logger с deinit. Продемонстрируйте вызов деинициализатора через блок do { }.

Упражнение 5. Перепишите на Swift с override и полиморфизмом:

class Notification:
def __init__(self, msg): self.msg = msg
def send(self): print(f"Уведомление: {self.msg}")
class EmailNotification(Notification):
def __init__(self, msg, email):
super().__init__(msg); self.email = email
def send(self): print(f"Email на {self.email}: {self.msg}")
class SMSNotification(Notification):
def __init__(self, msg, phone):
super().__init__(msg); self.phone = phone
def send(self): print(f"SMS на {self.phone}: {self.msg}")

Лекция 9. Перечисления и Pattern Matching

Упражнение 1. Создайте перечисление Coin с вариантами kopeck(Int), ruble(Int), dollar(Int) (ассоциированное значение — номинал). Напишите функцию totalInRubles(_ coins: [Coin]) -> Double, которая считает общую сумму в рублях (курс доллара = 90.0).

Упражнение 2. Создайте enum MathOperation с case add(Double, Double), subtract(Double, Double), multiply(Double, Double), divide(Double, Double). Напишите функцию calculate(_ op: MathOperation) -> Result<Double, String>, возвращающую результат или ошибку при делении на ноль (используйте собственный Result).

Упражнение 3. Создайте indirect enum FileSystemItem с вариантами file(name: String, size: Int) и folder(name: String, contents: [FileSystemItem]). Напишите функцию totalSize(_ item: FileSystemItem) -> Int, рекурсивно вычисляющую суммарный размер.

Упражнение 4. Дан массив значений enum Weather:

enum Weather {
case sunny(tempC: Double)
case rainy(tempC: Double, mmPrecipitation: Double)
case snowy(tempC: Double, cmSnow: Double)
case cloudy
}

С помощью for case let ... where выведите только дождливые дни с осадками более 10 мм.

Упражнение 5. Создайте конечный автомат для состояния пользователя: guest, loggedIn(username: String), banned(reason: String). Реализуйте struct UserSession с методами login(username:), ban(reason:), logout(), проверяющими допустимость перехода через guard case.


Лекция 10. Протоколы и расширения

Упражнение 1. Создайте протокол Payable с требованиями:

  • свойство salary: Double { get }
  • метод monthlyPay() -> Double

Реализуйте структуры FullTimeEmployee (ежемесячная выплата = salary / 12) и Contractor (ежемесячная выплата = salary * количество отработанных дней / рабочих дней). Создайте массив [Payable] и выведите информацию о каждом.

Упражнение 2. Создайте протокол Stackable с ассоциированными типами не используя — только методы push, pop, peek, isEmpty. Реализуйте структуру IntStack, соответствующую этому протоколу. Добавьте расширение с реализацией метода count.

Упражнение 3. Расширьте тип Double:

  • вычисляемое свойство km (конвертация километров в метры)
  • вычисляемое свойство celsius (создаёт строку с «°C»)
  • метод roundTo(places:) — округление до указанного количества знаков

Упражнение 4. Создайте протокол Serializable с методом toJSON() -> String. Добавьте реализацию по умолчанию через расширение протокола. Реализуйте две структуры, одна из которых переопределяет метод toJSON().

Упражнение 5. Перепишите следующий Python-код на Swift с использованием протоколов и расширений:

from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def perimeter(self) -> float: ...
def describe(self) -> str:
return f"Площадь: {self.area():.2f}, Периметр: {self.perimeter():.2f}"
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
import math
return math.pi * self.radius ** 2
def perimeter(self) -> float:
import math
return 2 * math.pi * self.radius
class Square(Shape):
def __init__(self, side: float):
self.side = side
def area(self) -> float:
return self.side ** 2
def perimeter(self) -> float:
return 4 * self.side
shapes = [Circle(5), Square(3)]
for s in shapes:
print(s.describe())

Упражнение 6. Создайте структуры Student и Course, соответствующие Equatable, Comparable, CustomStringConvertible и Hashable. Продемонстрируйте сортировку, поиск в Set и вывод через print().


Лекция 11. Обобщения (Generics)

Упражнение 1. Напишите обобщённую функцию filterItems<T>, принимающую массив [T] и замыкание (T) -> Bool, возвращающую массив элементов, удовлетворяющих предикату.

Упражнение 2. Создайте структуру Pair<A, B> с двумя значениями. Добавьте метод swapped() -> Pair<B, A>.

Упражнение 3. Реализуйте протокол Summable с associatedtype Element: Numeric и методом sum() -> Element. Реализуйте для структуры с массивом чисел.

Упражнение 4. Напишите removeDuplicates<T: Hashable>(from: [T]) -> [T] — массив без дубликатов с сохранением порядка.

Упражнение 5. Расширьте Stack<Element>: добавьте filter, а через where Element: Comparable — метод min() -> Element?.


Лекция 12. Обработка ошибок и управление памятью

Упражнение 1. Создайте enum ATMError: Error с кейсами insufficientFunds(required: Double), invalidPIN, cardBlocked. Напишите функцию withdraw(amount:pin:) throws, обработайте все ошибки в do-catch.

Упражнение 2. Напишите функцию divideAll(_ numbers: [Double], by divisor: Double) throws -> [Double], выбрасывающую ошибку при делении на ноль. Используйте try? и defer для логирования.

Упражнение 3. Создайте классы Author и Book с взаимными ссылками. Избегите retain cycle с помощью weak или unowned. Проверьте через deinit, что объекты освобождаются.

Упражнение 4. Создайте класс TaskRunner со свойством onComplete: (() -> Void)?. Продемонстрируйте утечку из-за захвата self в замыкании и исправьте её через [weak self].

Упражнение 5. Перепишите fetchUser(id:) из раздела 10, используя throws вместо Result. Сравните удобство обоих подходов.


Лекция 13. Конкурентность и асинхронное программирование

Упражнение 1. Напишите func delay(_ seconds: Double) async -> String, приостанавливающуюся на указанное время и возвращающую "Ожидание \(seconds) сек завершено". Вызовите с await.

Упражнение 2. С помощью async let запустите три вызова delay (1, 2 и 3 секунды) параллельно. Убедитесь, что общее время ~3 секунды, а не ~6.

Упражнение 3. Создайте func processItems(_ items: [String]) async -> [String] с withTaskGroup, параллельно переводящую строки в верхний регистр с имитацией задержки.

Упражнение 4. Напишите актор WordCounter со словарём [String: Int]. Метод count(word:) увеличивает счётчик, topWords(n:) возвращает n самых частых слов. Тестируйте из нескольких задач.

Упражнение 5. Реализуйте кооперативную отмену: задача обрабатывает массив с Task.checkCancellation(), отмените её через 0.3 секунды.

Упражнение 6. Перепишите упражнение 3 с withThrowingTaskGroup: строки короче 3 символов должны вызывать ошибку.


Лекция 14. Экосистема Swift и итоговый проект

Упражнение 1. Создайте Swift-пакет Greeting с функцией greet(name: String) -> String. Напишите тест, проверяющий результат. Запустите swift build и swift test.

Упражнение 2. Напишите CLI-утилиту, принимающую путь к JSON-файлу и выводящую его в отформатированном виде. Используйте Foundation и JSONSerialization.

Упражнение 3. Создайте Codable-структуру Config с полями host, port, debug. Реализуйте чтение из JSON-файла, обработайте ошибки через do-catch без force unwrapping.

Упражнение 4. Перепишите любой Python-скрипт на Swift. Сравните читаемость и типобезопасность.

Упражнение 5. Создайте Vapor-сервер с маршрутами GET /, GET /time, POST /echo. Протестируйте через curl.