PR3-Rust-SS26/I-homework/Homework.md

4.6 KiB

Rust Übungsaufagaben:

1. Ownership & Borrowing:

Aufgabe 1:

Erkläre, warum folgender Rust-Code nicht kompiliert:

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?

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:

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:

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<i32, String> 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.

fn parse_number(input: &str) -> Result<i32, String> {
    // 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?

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?

// 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:

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:

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:

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?

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.