Skip to content
Zurück zu den Lernmaterialien

Modul 2 — Sprachgrundlagen: Typen, Funktionen, Kontrollfluss

5. September 2026~2 min read
Lektion von 0/ abgeschlossen
Modul 2 — Foundations

Shadowing statt Mutation

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.

📝 Schnellprüfung

Was gibt dieses Programm aus?

✅ Wichtige Erkenntnisse

Haken setzen, um deinen Lernfortschritt zu markieren:

    Lektion von 0/ abgeschlossen
    Modul 2 — Foundations

    Datentypen: Skalare, Tupel, Arrays

    Skalare

    i8i128/u8u128 (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!

    Overflow selbst auslösenBereit
    Editor wird geladen…

    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.

    ✅ Wichtige Erkenntnisse

    Haken setzen, um deinen Lernfortschritt zu markieren:

      Lektion von 0/ abgeschlossen
      Modul 2 — Foundations

      Funktionen & die Tail Expression

      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.

      📝 Schnellprüfung

      Warum kompiliert fn add(a: i32, b: i32) -> i32 { a + b } ohne return?

      ✅ Wichtige Erkenntnisse

      Haken setzen, um deinen Lernfortschritt zu markieren:

        Lektion von 0/ abgeschlossen
        Modul 2 — Foundations

        Kontrollfluss: if, match, loop

        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.

        ✅ Wichtige Erkenntnisse

        Haken setzen, um deinen Lernfortschritt zu markieren:

          Modul-Checkpoint

          Checkpoint: Modul 2

          Bestehensgrenze: 80 %. Der Versuch wird bewertet und zählt für das Modul-Gate.

          Bereit, dein Wissen zu testen?

          Probiere unsere Übungsprüfungen mit Hunderten von realistischen Fragen aus.

          Üben starten →

          This site uses essential cookies for Stripe payments. No tracking cookies.