Funktionale Programmierung in Rust: von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Funktionale Programmierung in Rust: von A bis Z



Die Sprache Rust, bekannt für ihre sichere Speicherverwaltung und hohe Leistung, bietet auch leistungsstarke Werkzeuge für die funktionale Programmierung. Im Gegensatz zu rein funktionalen Sprachen (Haskell) ermöglicht Rust eine flexible Kombination von imperativen und funktionalen Stilen. In diesem Artikel werden wir die wichtigsten Konzepte der funktionalen Programmierung in Rust behandeln: von grundlegenden Closures bis hin zu fortgeschrittenen monadischen Mustern. Das Material ist sowohl für Anfänger als auch für erfahrene Entwickler nützlich, die prägnanteren und zuverlässigeren Code schreiben möchten.



1. Grundlagen: Unveränderlichkeit und Variablen



Funktionale Programmierung beginnt mit Unveränderlichkeit (Immutabilität). In Rust sind Variablen standardmäßig unveränderlich. Dies ist ein wesentlicher Unterschied zu vielen Sprachen.



// Unveränderliche Variable (Standard)let x = 10;// x = 20; // Kompilierungsfehler!

// Veränderliche Variable (explizit)let mut y = 5;y = 15; // Funktioniert


Die Verwendung von let ohne mut stellt sicher, dass sich der Wert nach der Initialisierung nicht ändert. Dies reduziert die Anzahl der Nebeneffekte und macht den Code vorhersagbarer. Im funktionalen Stil wird empfohlen, unveränderlichen Variablen den Vorzug zu geben und neue Werte zu erstellen, anstatt alte zu ändern.



2. Closures — anonyme Funktionen



Closures sind anonyme Funktionen, die Variablen aus ihrer Umgebung einfangen können. In Rust werden sie durch die Traits Fn, FnMut und FnOnce implementiert.



2.1. Syntax und Einfangen von Variablen



// Einfaches Closurelet add_one = |x: i32| -> i32 { x + 1 };println!("{}", add_one(5)); // 6

// Einfangen einer Variable aus der Umgebunglet base = 10;let add_base = |x| x + base; // base wird per Referenz (&) eingefangenprintln!("{}", add_base(20)); // 30

// Einfangen mit Mutation (FnMut)let mut counter = 0;let mut increment = || { counter += 1; };increment();increment();println!("{}", counter); // 2

// Einfangen mit Konsumierung (FnOnce)let name = String::from("Rust");let consume = || { drop(name); };consume();// println!("{}", name); // Fehler: name wurde verschoben


2.2. Closures als Funktionsargumente



Closures werden oft an Funktionen höherer Ordnung wie map, filter und fold übergeben.



let numbers = vec![1, 2, 3, 4, 5];

// Verwendung eines Closures mit filterlet evens: Vec<i32> = numbers .into_iter() .filter(|&x| x % 2 == 0) .collect();

println!("{:?}", evens); // [2, 4]


3. Iteratoren und Transformationsketten



Iteratoren sind das Herz der funktionalen Programmierung in Rust. Sie sind faul (Berechnungen erfolgen nur beim Aufruf von collect() oder for) und ermöglichen den Aufbau von Transformationsketten.



3.1. Basis-Adapter für Iteratoren



let data = vec![1, 2, 3, 4, 5, 6];

// Kette: filter -> map -> take -> collectlet result: Vec<i32> = data .iter() .filter(|&x| x % 2 == 0) // gerade Zahlen behalten .map(|x| x * 2) // verdoppeln .take(2) // die ersten beiden nehmen .collect();

println!("{:?}", result); // [4, 8]


3.2. Faltung (fold) und Reduktion



fold ist das Äquivalent zu reduce in anderen Sprachen. Es akkumuliert ein Ergebnis, während es alle Elemente durchläuft.



let numbers = [1, 2, 3, 4, 5];

// Summe aller Zahlenlet sum = numbers.iter().fold(0, |acc, &x| acc + x);println!("Sum: {}", sum); // 15

// Fakultätlet factorial = (1..=5).fold(1, |acc, x| acc * x);println!("5! = {}", factorial); // 120


3.3. Faule unendliche Iteratoren



// Unendlicher Iterator, nimm die ersten 10let first_ten: Vec<i32> = (0..)    .filter(|x| x % 2 == 0)    .map(|x| x * x)                

Blogs

Buchempfehlungen