# Rust Übungsaufagaben: ## 1. Ownership & Borrowing: ### Aufgabe 1: Erkläre, warum folgender Rust-Code nicht kompiliert: ```rust fn main() { let s1 = String::from("Hallo"); let s2 = s1; println!("{}", s1); } ``` Ändere den Code so, dass ```s1``` und ```s2``` augegeben werden können. ### Aufgabe 2: Warum verbietet Rust folgenden Code? ```rust fn main() { let mut text = String::from("Rust"); let r1 = &text; let r2 = &mut text; println!("{}", r1); println!("{}", r2); } ``` Schreibe den Code so um, sodass beide ```println!``` statements funktionieren. ## 2. Pattern Matching & Enums: ### Aufgabe 3: Gegeben sei folgender Rust Code für eine 3-Phasen Ampel: ```rust fn main(){ enum Ampel { Rot, Gelb, Gruen, } let ampel_status = Ampel::Rot; match ampel_status { Ampel::Rot => println!("STOP"), Ampel::Gelb => println!("Achtung"), Ampel::Gruen => println!("fahren"), } } ``` Ändere den Code in ```match ampel_status``` so ab, dass auch in ```Ampel``` beliebig viele andere Farben als Fahrsignal genutzt werden können. Was passiert wenn nicht alle Varainten in ```match ampel_status``` aufgelistet werden? ## 3. Option & Result Types: ### Aufgabe 4: Erkläre, warum folgender Code nicht funktioniert und behebe das Problem: ```rust fn main() { let numbers = vec![1, 2, 3, 4, 5]; let index = 10; let value = numbers[index]; println!("Wert: {}", value); } ``` Verwende `Option` oder eine andere Fehlerbehandlung, um sicher auf den Vektor zuzugreifen. Erkläre die Vorteile dieses Ansatzes gegenüber einem Laufzeitfehler ("panic"). ### Aufgabe 5: Schreibe eine Funktion `parse_number`, die einen String nimmt und ein `Result` zurückgibt: - Bei erfolgreicher Konvertierung: `Ok(zahl)` - Bei Fehler: `Err("Ungültige Eingabe".to_string())` Verwende danach die Funktion in `main()` und behandle das `Result` mit `match`. ```rust fn parse_number(input: &str) -> Result { // TODO: Implementierung } fn main() { // TODO: Funktion testen und Error Handling } ``` Wie unterscheidet sich `Result` von `Option`? Wann verwendet man welchen Typ? ## 4. String vs &str und Ownership: ### Aufgabe 6: Erkläre den Unterschied zwischen `String` und `&str`. Warum verbietet Rust folgende Funktion zu kompilieren? ```rust fn greet(name: &str) { println!("Hallo, {}!", name); } fn main() { let my_string = String::from("Alice"); let string_slice = "Bob"; greet(my_string); // Fehler? greet(string_slice); } ``` Behebe den Fehler und erkläre, warum die Verwendung von `&str` als Parameter flexibler ist. ### Aufgabe 7: Was ist der Unterschied zwischen folgenden zwei Funktionen? Welche ist besser und warum? ```rust // Variante 1: fn create_greeting_1(name: String) -> String { format!("Hallo, {}!", name) } // Variante 2: fn create_greeting_2(name: &str) -> String { format!("Hallo, {}!", name) } ``` Schreibe für beide Varianten ein Beispiel in `main()`, das die Flexibilität von Variante 2 demonstriert. ## 5. Traits und Polymorphismus: ### Aufgabe 8: Gegeben sind folgende Structs und ein Trait: ```rust struct Kreis { radius: f64, } struct Rechteck { width: f64, height: f64, } trait Flaeche { fn flaeche(&self) -> f64; } ``` Implementiere den `Flaeche` Trait für beide Structs. Schreibe dann eine Funktion, die eine Referenz auf ein Objekt mit `Flaeche` Trait annimmt und dessen Fläche ausgibt. Bonus: Erstelle einen Vektor mit verschiedenen Formen und iteriere über sie. ## 6. Mutability und Interior Mutability: ### Aufgabe 9: Erkläre, warum folgender Code nicht funktioniert: ```rust fn main() { let counter = 0; counter += 1; println!("Counter: {}", counter); } ``` Wie würde man diesen Code korrekt schreiben? Was ist der Unterschied zwischen `let mut` und Immutability? Gegeben ist ein Programm, das einen Counter mit einer Funktion erhöht: ```rust fn increment(counter: &mut i32) { *counter += 1; } fn main() { let mut count = 0; increment(&mut count); println!("Counter: {}", count); } ``` Erkläre die Rolle von `mut`, `&mut` und `*`. ## 7. Lifetimes: ### Aufgabe 10: Warum kompiliert folgender Code nicht und wie behebt man das Problem? ```rust fn longest(s1: &str, s2: &str) -> &str { if s1.len() > s2.len() { s1 } else { s2 } } fn main() { let string1 = String::from("abc"); let result; { let string2 = String::from("xyz"); result = longest(&string1, &string2); } println!("{}", result); } ``` Erkläre, was Lifetimes sind und warum Rust sie braucht. Behebe den Code mit korrekten Lifetime-Annotationen.