diff --git a/E-enums/01_enums_mit_daten.rs b/E-enums/01_enums_mit_daten.rs new file mode 100644 index 0000000..7e4f0de --- /dev/null +++ b/E-enums/01_enums_mit_daten.rs @@ -0,0 +1,25 @@ +// Jede Variante kann unterschiedliche Daten tragen. +enum Tier { + Hund(String), // Tupel-Variante: Name + Fisch { art: String, liter: u32 }, // Struct-Variante: benannte Felder + Stein, // Keine Daten +} + +fn main() { + let haustiere = vec![ + Tier::Hund("Bello".into()), + Tier::Fisch { + art: "Goldfisch".into(), + liter: 60, + }, + Tier::Stein, + ]; + + for tier in &haustiere { + match tier { + Tier::Hund(name) => println!("{name} will Gassi gehen"), + Tier::Fisch { art, liter } => println!("{art} braucht {liter}L Aquarium"), + Tier::Stein => println!("...braucht nichts."), + } + } +} diff --git a/E-enums/02_option.rs b/E-enums/02_option.rs new file mode 100644 index 0000000..557b25d --- /dev/null +++ b/E-enums/02_option.rs @@ -0,0 +1,21 @@ +// Option ersetzt null/nil. Der Compiler erzwingt, dass ihr den "nichts da"-Fall behandelt. + +fn teile(a: f64, b: f64) -> Option { + if b == 0.0 { + None // Kein Ergebnis möglich + } else { + Some(a / b) // Ergebnis einpacken + } +} + +fn main() { + let versuche = vec![(10.0, 3.0), (5.0, 0.0), (42.0, 7.0)]; + + for (a, b) in versuche { + // Ohne diesen match kompiliert der Code nicht ihr MÜSST den None-Fall behandeln. + match teile(a, b) { + Some(ergebnis) => println!("{a} / {b} = {ergebnis:.2}"), + None => println!("{a} / {b} = nicht möglich!"), + } + } +} diff --git a/E-enums/03_result.rs b/E-enums/03_result.rs new file mode 100644 index 0000000..8724f6d --- /dev/null +++ b/E-enums/03_result.rs @@ -0,0 +1,27 @@ +// Result modelliert Erfolg ODER Fehler. Jeder Fehlertyp ist eine eigene Enum Variante. + +#[derive(Debug)] //generiert automatisch eine Debug-Ausgabe +enum FehlerArt { + ZuKurz, + KeineZahl, +} + +// Rückgabe ist entweder Ok(eine_zahl) oder Err(ein_fehler) +fn parse_alter(input: &str) -> Result { + if input.len() < 1 { + return Err(FehlerArt::ZuKurz); + } + input.parse::().map_err(|_| FehlerArt::KeineZahl) +} + +fn main() { + let eingaben = vec!["25", "", "abc", "42"]; + + for e in eingaben { + match parse_alter(e) { + Ok(alter) => println!("\"{e}\" → Alter: {alter}"), + Err(FehlerArt::ZuKurz) => println!("\"{e}\" → Fehler: leere Eingabe"), + Err(FehlerArt::KeineZahl) => println!("\"{e}\" → Fehler: keine gültige Zahl"), + } + } +} diff --git a/E-enums/04_match_guards.rs b/E-enums/04_match_guards.rs new file mode 100644 index 0000000..0c80340 --- /dev/null +++ b/E-enums/04_match_guards.rs @@ -0,0 +1,16 @@ +// Match Guards: ein `if` nach dem Pattern fügt eine zusätzliche Bedingung hinzu. + +fn bewerte_note(punkte: u32) { + match punkte { + p if p >= 90 => println!("{p} Punkte → Sehr gut"), + p if p >= 75 => println!("{p} Punkte → Gut"), + p if p >= 50 => println!("{p} Punkte → Bestanden"), + p => println!("{p} Punkte → Durchgefallen"), + } +} + +fn main() { + for p in [95, 80, 55, 30] { + bewerte_note(p); + } +} diff --git a/E-enums/05_verschachtelt.rs b/E-enums/05_verschachtelt.rs new file mode 100644 index 0000000..7af3995 --- /dev/null +++ b/E-enums/05_verschachtelt.rs @@ -0,0 +1,55 @@ +// Patterns können beliebig tief verschachtelt werden: +// Structs in Enums in Options – alles in einem match. + +enum Inhalt { + Text(String), + Zahl(i32), +} + +struct Paket { + absender: String, + inhalt: Option, +} + +fn oeffne(p: &Paket) { + match p { + // Option UND Enum gleichzeitig destrukturieren + Paket { + absender, + inhalt: Some(Inhalt::Text(t)), + } => { + println!("Von {absender}: Text \"{t}\""); + } + Paket { + absender, + inhalt: Some(Inhalt::Zahl(n)), + } => { + println!("Von {absender}: Zahl {n}"); + } + // .. deckt restliche Felder ab (hier: absender) + Paket { inhalt: None, .. } => { + println!("Leeres Paket."); + } + } +} + +fn main() { + let pakete = vec![ + Paket { + absender: "Alice".into(), + inhalt: Some(Inhalt::Text("Hallo".into())), + }, + Paket { + absender: "Bob".into(), + inhalt: Some(Inhalt::Zahl(99)), + }, + Paket { + absender: "Eve".into(), + inhalt: None, + }, + ]; + + for p in &pakete { + oeffne(p); + } +} diff --git a/E-enums/06_exhaustiveness.rs b/E-enums/06_exhaustiveness.rs new file mode 100644 index 0000000..452c8df --- /dev/null +++ b/E-enums/06_exhaustiveness.rs @@ -0,0 +1,24 @@ +// Exhaustiveness: der Compiler prüft, ob ALLE Varianten abgedeckt sind. Vergisst man eine → Compilerfehler. + +enum Ampel { + Rot, + Gruen, + // Gelb, // ← einkommentieren und neu kompilieren! +} + +fn aktion(a: &Ampel) -> &str { + match a { + Ampel::Rot => "Stehen bleiben", + Ampel::Gruen => "Gehen", + // Ohne Arm für Gelb → Compilerfehler: + // "non-exhaustive patterns: `Gelb` not covered" + } +} + +fn main() { + let ampeln = [Ampel::Rot, Ampel::Gruen]; + + for a in &eln { + println!("{}", aktion(a)); + } +} diff --git a/E-enums/TODO b/E-enums/TODO deleted file mode 100644 index e69de29..0000000 diff --git a/F-error/01_testing.rs b/F-error/01_testing.rs new file mode 100644 index 0000000..7bc6a04 --- /dev/null +++ b/F-error/01_testing.rs @@ -0,0 +1,38 @@ +// Tests werden mit "cargo test" ausgeführt + +fn is_even(n: i32) -> bool { + n % 2 == 0 +} + +fn double(n: i32) -> i32 { + n * 2 +} + +fn add_one(n: i32) -> i32 { + n + 1 +} +fn main() { + println!("{} ist gerade: {}", 4, is_even(4)); + println!("doppelt von 5: {}", double(5)); +} + +// Tests liegen generell im selben file wie die Function selbst +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn even() { + assert!(is_even(4)); // bool + } + + #[test] + fn double_of_5() { + assert_eq!(double(5), 10); // Vergleich auf Gleichheit + } + + #[test] + fn add_one_changes_value() { + assert_ne!(add_one(5), 5); // Vergleich auf Ungleichheit + } +} diff --git a/F-error/TODO b/F-error/TODO deleted file mode 100644 index e69de29..0000000