Funktionen in Rust
Definiere Funktionen mit fn, gib Werte zurueck, nutze Parameter und lerne den Unterschied zwischen expliziten return und impliziten Ausdruecken.
Inhaltsverzeichnis
Funktionen in Rust
Funktionen sind das Grundgeruest jedes Rust-Programms. Du hast sie schon genutzt: main, println! (okay, das war ein Makro) und diverse Methoden.
Grundform
fn begruessen() {
println!("Hallo!");
}
fn main() {
begruessen();
}
fnleitet die Funktion einsnake_caseist die Konvention fuer Funktionsnamen()listet Parameter auf (hier: keine){}umschliesst den Funktionsrumpf
Parameter
Jeder Parameter braucht einen expliziten Typ - der Compiler leitet das hier nicht ab:
fn begruessen(name: &str) {
println!("Hallo, {}!", name);
}
fn main() {
begruessen("Anna");
begruessen("Leo");
}
Mehrere Parameter werden mit Kommas getrennt:
fn addiere(a: i32, b: i32) {
println!("{} + {} = {}", a, b, a + b);
}
Rueckgabewerte
Der Rueckgabetyp steht hinter ->:
fn addiere(a: i32, b: i32) -> i32 {
a + b // keine Semikolon - das ist der Rueckgabewert!
}
fn main() {
let ergebnis = addiere(3, 4);
println!("{}", ergebnis); // 7
}
Explizites return
Du kannst auch return benutzen - besonders bei frueher Rueckkehr:
fn sicher_teilen(a: f64, b: f64) -> f64 {
if b == 0.0 {
return 0.0; // fruehzeitiges return
}
a / b
}
Expression vs. Statement
Erinnere dich an den Unterschied:
- Statement endet mit
;und liefert keinen Wert - Expression liefert einen Wert
Eine Funktion gibt ihren letzten Expression-Wert zurueck. Wenn du ein Semikolon setzt, wird daraus ein Statement und die Funktion gibt () zurueck (den sogenannten โunit typeโ).
fn broken() -> i32 {
5 + 3; // FEHLER: Semikolon macht das zum Statement
// erwartet i32, bekommt ()
}
fn korrekt() -> i32 {
5 + 3 // kein Semikolon
}
Funktionen mit mehreren Rueckgabewerten
Rust hat kein spezielles Multi-Return, aber Tupel erfuellen den Zweck:
fn min_max(zahlen: &[i32]) -> (i32, i32) {
let mut min = zahlen[0];
let mut max = zahlen[0];
for &z in zahlen {
if z < min { min = z; }
if z > max { max = z; }
}
(min, max)
}
fn main() {
let zahlen = [3, 1, 4, 1, 5, 9, 2, 6];
let (min, max) = min_max(&zahlen);
println!("min = {}, max = {}", min, max);
}
Bloecke als Ausdruecke
Innerhalb einer Funktion kannst du Bloecke als Ausdruecke nutzen:
fn main() {
let wetter = "Regen";
let kleidung = if wetter == "Sonne" {
"T-Shirt"
} else {
"Jacke"
};
println!("Zieh eine {} an", kleidung);
}
Einfaches Beispiel: Zahl raten
fn ist_gerade(n: i32) -> bool {
n % 2 == 0
}
fn beschreibe(n: i32) -> String {
if ist_gerade(n) {
format!("{} ist gerade", n)
} else {
format!("{} ist ungerade", n)
}
}
fn main() {
for i in 1..=5 {
println!("{}", beschreibe(i));
}
}
Kleine Stilregeln
- snake_case fuer Namen:
ist_gerade, nichtistGerade - Funktionen kurz halten: wenn eine Funktion viel mehr tut als ihr Name verspricht, zerlegen
- Rueckgabetypen anzeigen - auch wenn Rust sie manchmal herleiten koennte, mach es dem Leser einfach
Uebersicht
fn name(parameter: Typ) -> Rueckgabe { ... }- Parameter brauchen immer einen expliziten Typ
- Der letzte Ausdruck ohne Semikolon ist der Rueckgabewert
- Frueher Ausstieg mit
return - Tupel fuer Multi-Return
snake_caseals Konvention
Als Naechstes wird es spannend: Das Ownership-System, das Herzstueck von Rust.