Функциональное программирование в Swift: основы и примеры

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в функциональное программирование в Swift

Swift — это мультипарадигмальный язык программирования, разработанный Apple для создания приложений под iOS, macOS, watchOS и tvOS. Помимо объектно-ориентированного и протокольно-ориентированного подходов, Swift активно поддерживает функциональное программирование. Этот стиль основан на использовании чистых функций, иммутабельности данных и отказе от побочных эффектов.

Функциональное программирование делает код более предсказуемым, тестируемым и параллельно безопасным. В этой статье мы разберём ключевые концепции функционального подхода в Swift: неизменяемость, функции высшего порядка, замыкания и цепочки методов. Вы увидите, как с помощью map, filter и reduce писать лаконичный и выразительный код.

Основы функционального подхода в Swift

Иммутабельность (неизменяемость)

В функциональном программировании данные не изменяются после создания. Вместо изменения существующего объекта создаётся новый. Swift поощряет этот подход с помощью ключевого слова let для объявления констант.

// Иммутабельное значение
let numbers = [1, 2, 3, 4, 5]
// numbers.append(6) // Ошибка компиляции — numbers неизменяем

// Создание нового массива
let newNumbers = numbers + [6]
print(newNumbers) // [1, 2, 3, 4, 5, 6]

Использование let вместо var помогает избежать случайных изменений состояния и упрощает отладку.

Функции как объекты первого класса

В Swift функции — это объекты первого класса. Их можно присваивать переменным, передавать как аргументы и возвращать из других функций.

// Функция, присвоенная переменной
let multiply: (Int, Int) -> Int = { $0 * $1 }
print(multiply(3, 4)) // 12

// Функция, принимающая другую функцию
func applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}

let result = applyOperation(10, 5, operation: multiply)
print(result) // 50

Замыкания (Closures) в Swift

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

// Простое замыкание
let greeting = { (name: String) -> String in
    return "Привет, \(name)!"
}
print(greeting("Мир")) // Привет, Мир!

// Сокращённая форма с параметрами
let numbers = [3, 1, 4, 1, 5, 9]
let sorted = numbers.sorted { $0 < $1 }
print(sorted) // [1, 1, 3, 4, 5, 9]

Замыкания делают код компактным и выразительным, особенно при работе с коллекциями.

Функции высшего порядка: map, filter, reduce

Это три столпа функционального программирования в Swift. Они позволяют обрабатывать массивы, словари и другие коллекции без явных циклов.

map — преобразование каждого элемента

Метод map применяет замыкание к каждому элементу коллекции и возвращает новый массив с результатами.

let prices = [100, 200, 300, 400]
let discounted = prices.map { $0 * 0.9 }
print(discounted) // [90.0, 180.0, 270.0, 360.0]

// Работа со строками
let names = ["Анна", "Борис", "Виктор"]
let uppercased = names.map { $0.uppercased() }
print(uppercased) // ["АННА", "БОРИС", "ВИКТОР"]

filter — отбор по условию

filter возвращает новый массив, содержащий только те элементы, которые удовлетворяют заданному условию.

let scores = [45, 78, 92, 33, 88, 61]
let passingScores = scores.filter { $0 >= 60 }
print(passingScores) // [78, 92, 88, 61]

// Фильтрация строк
let words = ["Swift", "iOS", "macOS", "функция"]
let shortWords = words.filter { $0.count <= 4 }
print(shortWords) // ["iOS", "macOS"]

reduce — свёртка коллекции

reduce объединяет все элементы коллекции в одно значение, используя заданное замыкание и начальное значение.

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce(0, +)
print(sum) // 15

// Конкатенация строк
let words = ["Функциональное", "программирование", "в", "Swift"]
let sentence = words.reduce("") { $0.isEmpty ? $1 : $0 + " " + $1 }
print(sentence) // Функциональное программирование в Swift

Практический пример: обработка данных пользователей

Представьте, что у вас есть массив пользователей, и вам нужно получить список имён активных пользователей старше 18 лет, отсортированных по возрасту. Функциональный подход позволяет сделать это в одну цепочку вызовов.

struct User {
    let name: String
    let age: Int
    let isActive: Bool
}

let users = [
    User(name: "Анна", age: 25, isActive: true),
    User(name: "Борис", age: 17, isActive: true),
    User(name: "Виктор", age: 30, isActive: false),
    User(name: "Галина", age: 22, isActive: true)
]

let activeAdultNames = users
    .filter { $0.isActive && $0.age >= 18 }
    .sorted { $0.age < $1.age }
    .map { $0.name }

print(activeAdultNames) // ["Галина", "Анна"]

Этот код читается как описание задачи: «отфильтровать активных взрослых, отсортировать по возрасту, взять имена». Никаких временных переменных или циклов — только чистые преобразования.

Заключение

Функциональное программирование в Swift — это мощный инструмент, который делает код более лаконичным, безопасным и легко тестируемым. Используя иммутабельность, замыкания и функции высшего порядка (map, filter, reduce), вы сможете писать вырази

Блоги

Рекомендаций по книгам