v3.1.0Kontrollfluss

Pattern Matching

Das match Statement ist wie ein switch auf Steroiden - mit Exhaustiveness Check, Guards und Destructuring.

Grundlegendes Matching

match prüft einen Wert gegen eine Reihe von Mustern und führt den ersten passenden Zweig aus. Der Compiler prüft bei Enums, ob alle Fälle abgedeckt sind (Exhaustiveness Check).

let status = 404;

match status {
    200 => log.info("Alles OK"),
    404 => log.error("Nicht gefunden"),
    500 => log.error("Server Fehler"),
    _   => log.warn("Unbekannter Status") // Wildcard fängt alles andere
}

Pattern Types

Exakte Werte matchen:

match value {
    "hello" => log.info("Greeting"),
    42 => log.info("The Answer"),
    true => log.info("Truthy"),
    _ => log.info("Something else")
}

Guards (Zusätzliche Bedingungen)

Guards erlauben zusätzliche if-Bedingungen an Pattern:

let value = Result::Ok(42);

match value {
    Ok(x) if x > 0 => "positive",
    Ok(x) if x < 0 => "negative",
    Ok(0) => "zero",
    Err(e) => "error: " + e,
    _ => "unknown"
}

// Komplexere Guards
match user {
    User { age, role: "admin" } if age >= 18 => {
        log.info("Volljähriger Admin");
    },
    User { age } if age < 13 => {
        log.info("Kind");
    },
    User { name } => {
        log.info("Normaler User: " + name);
    }
}

Enum Matching

Pattern Matching ist besonders mächtig mit Enums (Algebraic Data Types):

enum Status { 
    Idle, 
    Running(number),    // Fortschritt in Prozent
    Error(string) 
}

fn checkStatus(s: Status) {
    match s {
        Status.Idle => log.info("System ist bereit."),
        Status.Running(p) => log.info("Verarbeitung: " + p + "%"),
        Status.Error(msg) => log.error("Kritischer Fehler: " + msg),
    }
}

// Payment Enum
enum PaymentMethod {
    Cash,
    CreditCard(string),    // Kartennummer
    PayPal(string),        // Email
}

fn processPayment(method: PaymentMethod) {
    match method {
        PaymentMethod.Cash => {
            log.info("Barzahlung empfangen");
        },
        PaymentMethod.CreditCard(num) => {
            log.info("Karte wird belastet: ****" + num.slice(-4));
        },
        PaymentMethod.PayPal(email) => {
            log.info("PayPal-Zahlung an: " + email);
        }
    }
}

Result & Optional Matching

// Result Matching
let result = parseNumber("42");

match result {
    Ok(value) => log.info("Parsed: " + value),
    Err(error) => log.error("Parse Error: " + error)
}

// Optional Matching
let user = findUser("123");

match user {
    Some(u) => log.info("Gefunden: " + u.name),
    None => log.warn("User nicht gefunden")
}

// Kombiniert mit Guards
match fetchData(url) {
    Ok(data) if data.length() > 0 => processData(data),
    Ok(_) => log.warn("Leere Antwort"),
    Err(e) if e.code == 404 => log.info("Nicht gefunden"),
    Err(e) => log.error("Fehler: " + e.message)
}

Vorteile gegenüber If-Else

Sicherheit

Der Compiler warnt, wenn ein Fall vergessen wurde (Exhaustiveness)

Lesbarkeit

Klare Strukturierung von komplexen Verzweigungen

Performance

Intern als effiziente Sprungtabelle (Jump Table) in Rust implementiert

Best Practices

Wildcard zuletzt

Setze _ immer als letzten Arm

Spezifisch zu allgemein

Ordne Patterns von spezifisch nach allgemein

Guards sparsam

Verwende Guards nur wenn nötig

Destructure nur was du brauchst

Ignoriere ungenutzte Felder mit _