Modul 2 — Sprachgrundlagen: Typen, Funktionen, Kontrollfluss
Shadowing, skalare und zusammengesetzte Typen, der Tail-Expression-Trick, if/match/loop — mit Laufzeit-Panics, die du im Playground selbst auslösen kannst.
Shadowing statt Mutation
Lektion 5 von 4
Rust erlaubt es, eine Variable neu zu deklarieren — die alte Bindung wird überschattet:
fn main() {
let x = 5;
let x = x + 1; // neue Bindung, alte ist ab hier unsichtbar
println!("{x}"); // 6
}
Der feine Unterschied zu mut: Shadowing erzeugt eine neue Bindung, die
auch einen anderen Typ haben darf:
let spaces = " "; // &str
let spaces = spaces.len(); // usize — komplett anderer Typ, völlig legal
Mit mut müsste der Typ gleich bleiben. Shadowing ist der idiomatische Weg
für "wandle einen Wert Schritt für Schritt um", ohne Namen wie spaces2
zu erzeugen.
Shadowing ≠ Mutation
Shadowing: neue Bindung, neuer Typ möglich, alte Bindung bleibt unverändert
(bis zum Scope-Ende). mut: dieselbe Bindung, derselbe Typ, Wert ändert sich.
Praxis-Szenario: Der Datenimport
Ein CSV-Import liefert alle Werte als Strings. Der Prototyp rechnet mit Rohwerten weiter — das Ergebnis stimmt nie. Dein Kollege will Parsing-Code überall einbauen; du schlägst Shadowing mit sauberen Typen vor.
Übung: Variablen überschatten
🧩 Übung m2-l5-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Datentypen: Skalare, Tupel, Arrays
Lektion 6 von 4
Skalare
i8–i128/u8–u128 (Vorzeichen ja/nein), f32/f64, bool, char.
Der Default ist i32 bzw. f64.
fn main() {
let a: i32 = -42;
let b: u8 = 255; // größter u8-Wert
let c = 2.5_f64;
let letter = 'z'; // char: EIN Unicode-Skalarpunkt, einfache Quotes
let s = "z"; // &str: String-Slice, doppelte Quotes
}
Integer-Overflow: Panik im Debug, Wrap im Release
fn inc(x: u8) -> u8 {
x + 1
}
fn main() {
println!("{}", inc(255));
}
Typkorrekt — der Compiler akzeptiert es. Aber im Debug-Build bricht das
Programm zur Laufzeit mit attempt to add with overflow ab, im Release-
Build wrappt es still auf 0. Probiere es im Playground aus!
Tupel und Arrays
fn main() {
let t = (1, 2.5, "three"); // Tupel: gemischt, feste Größe
println!("{}", t.0); // 1 — Zugriff per Punkt-Index
let a = [1, 2, 3]; // Array: gleichartig, Stack, feste Größe
println!("{}", a[1]); // 2 — Laufzeit-Indexcheck
}
Indexieren ist zur Laufzeit geprüft: a[5] kompiliert (bei Variable als
Index), paniziert aber mit index out of bounds — Rust liest nie fremden
Speicher.
Übung: Tupel-Zugriff
🧩 Übung m2-l6-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Funktionen & die Tail Expression
Lektion 7 von 4
fn add(a: i32, b: i32) -> i32 {
a + b
}
Kein return, kein Semikolon: Die letzte Anweisung ohne Semikolon ist der
Rückgabewert. Die Semikolon-Regel ist die wichtigste neue Gewohnheit
für Einsteiger:
fn broken(a: i32, b: i32) -> i32 {
a + b; // ❌ Semikolon macht daraus eine Anweisung vom Typ ()
} // ❌ E0308: expected i32, found ()
Parameter-Typen sind Pflicht, Rückgabetyp steht nach dem Pfeil. () (unit)
ist Rusts "nichts" — der Typ von Anweisungen.
Semikolon = Wert wegwerfen
expr; wertet expr aus und verwirft das Ergebnis (Typ ()). Lässt du das
Semikolon weg, ist der Ausdruck der Wert. Das gilt in Blöcken, if-Armen und
Funktionskörpern gleichermaßen.
Übung: Tail-Expression in Funktionen
🧩 Übung m2-l7-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Kontrollfluss: if, match, loop
Lektion 8 von 4
if ist ein Ausdruck
fn main() {
let a = 3;
let b = 7;
let max = if a > b { a } else { b };
println!("{max}"); // 7
}
Beide Arme müssen denselben Typ haben — sonst kann der Compiler den Typ des Gesamtausdrucks nicht bestimmen. Keine Klammern um die Bedingung, dafür geschweifte Klammern Pflicht.
match: erschöpfend by Design
fn main() {
let n = 3;
let label = match n {
1 => "one",
3 => "three",
_ => "many",
};
println!("{label}"); // three
}
Der Compiler verlangt Vollständigkeit: Jeder mögliche Wert muss von einem
Arm abgedeckt sein. Der Wildcard-Arm _ fängt den Rest. Vergessen wir ihn,
kompiliert es nicht — eine ganze Fehlerklasse zur Compile-Zeit erledigt.
loop mit Wert
fn main() {
let mut count = 0;
let result = loop {
count += 1;
if count == 10 {
break count * 2; // loop kann einen Wert liefern
}
};
println!("{result}"); // 20
}
while und for (über Bereiche: for i in 0..5) ergänzen das Repertoire —
loop ist aber die einzige Schleife, die als Ausdruck einen Wert liefern
kann.
Übung: match und loop
🧩 Übung m2-l8-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren: