Funktionale Programmierung in Swift: Von Closures zur Komposition
Swift wurde ursprünglich als Multi-Paradigmen-Sprache entwickelt. Sie unterstützt objektorientierte, protokollorientierte und funktionale Programmierung. Der funktionale Ansatz hilft dabei, vorhersagbareren, testbareren und nebenläufigkeitssicheren Code zu schreiben. In diesem Artikel werden wir die wichtigsten Konzepte der funktionalen Programmierung in Swift anhand praktischer Beispiele erläutern.
1. Reine Funktionen und Unveränderlichkeit
Die Grundlage des funktionalen Stils sind reine Funktionen. Eine solche Funktion gibt für die gleichen Argumente immer das gleiche Ergebnis zurück und hat keine Nebenwirkungen (ändert keinen externen Zustand).
// Unreine Funktion — verändert eine externe Variablevar total = 0func addToTotal(_ value: Int) -> Int { total += value return total}
// Reine Funktion — nur Berechnungfunc add(_ a: Int, _ b: Int) -> Int { return a + b}Unveränderlichkeit wird durch let und Strukturen mit Wertesemantik erreicht. Anstatt ein Array zu verändern, erstellen wir ein neues:
let numbers = [1, 2, 3, 4, 5]// Anstelle von var und append:let newNumbers = numbers + [6] // [1, 2, 3, 4, 5, 6]2. Closures als Bausteine
Closures in Swift sind anonyme Funktionen, die Variablen aus ihrem umgebenden Kontext erfassen können. Sie sind "Erstklassige Bürger": Sie können als Parameter übergeben und von Funktionen zurückgegeben werden.
// Einfache Closurelet multiply: (Int, Int) -> Int = { $0 * $1 }let result = multiply(3, 4) // 12
// Closure mit Kontexterfassungvar counter = 0let increment = { counter += 1 }increment() // counter = 1increment() // counter = 2Closures werden aktiv in Methoden höherer Ordnung wie sorted verwendet:
let names = ["Ivan", "Anna", "Boris", "Elena"]let sorted = names.sorted { $0.localizedStandardCompare($1) == .orderedAscending }print(sorted) // ["Anna", "Boris", "Elena", "Ivan"]3. Methoden höherer Ordnung: map, filter, reduce
Dies sind die "Arbeitstiere" des funktionalen Stils in Swift. Sie ermöglichen die Verarbeitung von Sammlungen ohne explizite Schleifen und Mutation.
map
Transformiert jedes Element der Sammlung:
let prices = [100, 200, 300]let withTax = prices.map { $0 * 1.2 }print(withTax) // [120.0, 240.0, 360.0]
// Praxisbeispiel: Namen aus einem Array von Modellen extrahierenstruct User { let name: String let age: Int}let users = [User(name: "Alexey", age: 30), User(name: "Maria", age: 25)]let userNames = users.map { $0.name }print(userNames) // ["Alexey", "Maria"]filter
Wählt Elemente basierend auf einer Bedingung aus:
let numbers = [1, 2, 3, 4, 5, 6]let evenNumbers = numbers.filter { $0 % 2 == 0 }print(evenNumbers) // [2, 4, 6]
// Benutzer filtern, die älter als 18 sindlet adults = users.filter { $0.age >= 18 }reduce
Reduziert die Sammlung auf einen einzelnen Wert:
let sum = numbers.reduce(0, +) // 21// Einen String aus einem Array erstellenlet words = ["Functional", "programming", "Swift"]let sentence = words.reduce("") { $0.isEmpty ? $1 : $0 + " " + $1 }print(sentence) // "Functional programming Swift"Kombinieren von Methoden
Der interessanteste Teil ist das Verketten von Methoden:
let transactions = [250, -50, 100, -200, 300, -100]let balance = transactions .filter { $0 > 0 } // nur Einnahmen .map { $0 * 0.87 } // 13% Steuer abziehen .reduce(0, +) // aufsummierenprint(balance) // 565.54. Funktionskomposition und Currying
Komposition ermöglicht es, mehrere Funktionen zu einer zu kombinieren. Swift hat keinen eingebauten Kompositionsoperator