⚑ Lehrpfad 3: Traits, Generics & Smart Pointer

Rust 09: Traits & Shared Behavior

Definiere gemeinsame Schnittstellen mit trait, implementiere Default-Verhalten, nutze Trait Bounds (T: Trait) und kombiniere Supertraits fΓΌr typsichere Abstraktionen.

πŸ“‚ Dateien dieser Lerneinheit:
πŸ“„ aufgabe.rs (Startercode) πŸ§ͺ test_aufgabe.rs (Tests) πŸ’‘ musterloesung.rs (LΓΆsung) πŸ“– README.md

⚑ 1. Was sind Traits?

Ein Trait (vergleichbar mit Interfaces in Java oder C#, aber deutlich mΓ€chtiger) definiert gemeinsame FunktionalitΓ€t, die verschiedene Datentypen teilen kΓΆnnen. Ein Trait beschreibt Methoden-Signaturen, die implementierende Typen bereitstellen mΓΌssen.

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚      trait TelemetryReport       β”‚
            β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
            β”‚ + summary(&self) -> String       β”‚
            β”‚ + severity_level(&self) -> u8    β”‚ (Default: 1)
            β”‚ + is_critical(&self) -> bool     β”‚ (Default: sev >= 8)
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚ impl Trait for Type
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β–Ό                                 β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   struct CpuMetric    β”‚       β”‚   struct DiskAlert    β”‚
β”‚ usage_percent: f64    β”‚       β”‚ device: String        β”‚
β”‚ core_id: usize        β”‚       β”‚ free_space_gb: u32    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
pub trait Summary {
    // Erforderliche Methode
    fn summarize(&self) -> String;

    // Methode mit Default-Implementierung
    fn is_highlighted(&self) -> bool {
        false
    }
}

pub struct NewsArticle {
    pub headline: String,
    pub author: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}: {}", self.headline, self.author)
    }
}

πŸ›‘οΈ 2. Trait Bounds & Mehrfach-EinschrΓ€nkungen

Mit Trait Bounds legst du fest, dass ein generischer Typ bestimmte Eigenschaften aufweisen muss. Mehrere Bounds werden mit + kombiniert:

1. Syntax mit impl Trait

Kompakt fΓΌr einfache Parameter: fn notify(item: &impl Summary)

2. Trait Bound Syntax

Erzwingt gleiche Typen: fn notify<T: Summary + Display>(item: &T)

3. where Clauses

ErhΓΆht Lesbarkeit bei vielen Typ-Parametern und komplexen Bounds.

// Mehrere Bounds mit 'where' Klausel
fn process_telemetry<T, U>(report: &T, target: &U) -> String
where
    T: Summary + Clone,
    U: std::fmt::Display,
{
    format!("Sende Report [{}] an Target [{}]", report.summarize(), target)
}

πŸ“‘ 3. Cheat-Sheet: Traits & Best Practices

Konzept Syntax / Rust-Code Bedeutung
Trait Definition pub trait Describable { fn desc(&self) -> String; } Definiert gemeinsame Methodensignaturen
Default Implementation fn is_ok(&self) -> bool { true } Kann bei Bedarf im impl ΓΌberschrieben werden
Mehrfach-Bounds T: Summary + Clone + Send Typ muss alle angegebenen Traits erfΓΌllen
Return impl Trait fn create_reporter() -> impl Summary Kapselt den konkreten Typ vor dem Aufrufer

🎯 Aufgaben & Checkliste in aufgabe.rs

πŸ’‘ Rustacean Tipp: Das Orphan Rule Prinzip

In Rust kannst du einen Trait nur fΓΌr einen Typen implementieren, wenn entweder der Trait oder der Typ in deiner eigenen Crate definiert ist. Das verhindert Namenskonflikte und sorgt fΓΌr StabilitΓ€t im Γ–kosystem!

πŸ’» In Web-IDE ΓΆffnen → Weiter zu Rust 10: Generics →