Reflexionen über die Programmiersprache Rust 22

in #deutsch2 days ago

*Komplexe Datentypen
Strukturen

Ich muss sagen, manches hinterlässt bei mir einen verwirrenden Eindruck, denn vieles was ich lerne (und schreibe) erweckt den Eindruck eines Deja Vus. Das ist wie bei den bereits beschriebenen Enums, es klingt alles logisch und solide, aber was genau mache ich mit dem Teil dann tatsächlich? Wenn ich bei Enums nur eine Sache jeweils auf einmal verwenden wollte, könnte man die Strukturen als eine Art von Sammelbox bezeichnen, welche die Eigenschaften eines Objekts beinhalten. Wichtig dabei ist, der weitere Nutzen einer solchen Struktur sollte gegeben sein. Also, alles was sich sicher auf andere Objekte übertragen lässt. Das könnte zB sein: Eine Personenbeschreibung, Eigenschaften von einem Auto, Eigenschaften von einem Computer, Eine Preisliste mit vergleichbaren Produkteigenschaften. Machen wirs (alleine schon, weil ich es so vorgefertigt habe) mit einem Auto. Schauen wir uns am Besten mal die Struktur einer Struktur an (das war wohl zwangsläufig).

Am Anfang war die Struktur, diese wollte Elemente und Datentypen. Doch dann begab es sich, dass diese weitere Strukturen ihrer Art verschlingen wollte. Und ich warf sie ihr zum Fraß vor.

struct Car{
    name: String,
    modell: String,
    baujahr: i32,
    ps:i16,
}

Ok, hier sehen wir den Grundaufbau einer Struktur, eigentlich nichts Besonderes. Da ist das Schlüsselwort struct, und in geschweiften Klammern befinden sich die Elemente, die in diesem Struct sein sollen. Es sind jeweils der Name und mit Doppelpunkt getrennt der Datentyp. Am Ende befindet sich kein Semikolon, sondern der bereits bekannte Beistrich bei Aufzählungen in solchen Datentypen. Struct befindet sich außerhalb von main() und wird innerhalb von main() verwendet/befüllt. Und zwar so:

fn main (){

    let car1 = Car{
        name:String::from("Opel"),
        modell:String::from("Vectra"),
        baujahr:1992,
        ps:75,
    };

Man sieht, dass die Variable car1 zu einer Instanz von Car wird. Die Syntax entspricht

let Variable = Strukturname{ 
Aufruf des Elements:Befüllen des Elements, je nach vorgegebenen Datentyp
};
//Am Ende noch ein Semikolon.

Das sieht dann in der Ausgabe so aus

println!("Name:{}\nModell:{}\nBaujahr:{}\nPS:{}\n",car1.name, car1.modell, car1.baujahr, car1.ps);

image.png

Eine zweite Instanz kann man genau so einfach bauen, aber diesmal mache ein paar einfache Fehler rein, damit wir auch eine Änderung/Korrektur sehen können.

let mut car2 = Car{
        name:String::from("Daca"),
        modell:String::from("Logan"),
        baujahr:2006,
        ps:87,
    };

Der Name und das Baujahr ist falsch. Das weiß ich, es ist mein alter Kübel.
Um das anzupassen, muss nur wie in der println! Anweisung ein Punkt zwischen Variable und Strukturelement eingefügt werden.

car2.name = String::from("Dacia");
car2.baujahr = 2009;

Damit werden die alten Werte überschrieben.

image.png

Kopien von Strukturen anlegen

Es kann gelegentlich passieren, dass Strukturen fast gänzlich gleiche Eigenschaften aufweisen.Da wäre es blöd, wenn man die ganze Litanei von vorne bis hinten schreiben müsste. Dafür gibt es (wer hätte das gedacht?) Abhilfe.

Nehmen wir einfach das Autobeispiel her und es ist nur die Farbe anders.
Dazu habe ich das Struct Beispiel etwas angepasst, sonst wird es verwirrend.
Also, jetzt haben die Autos auch eine bestimmte Farbe. Bevor wir hier weitermachen können, ein Hinweis, dass Strings nicht einfach kopiert werden können. Ich habe aus diesem Grund fürs Erste mal eine Struktur nur mit Zahlen gebaut, damit mal der bequeme Teil sichtbar ist.

Das ist die Basis von dem ausgegangen wird.

struct Zahlen{
    eins: u8,
    zwei: u8,
    drei: u8,
    vier: u8,
}   

4 kleine Zahlen werden erwartet. Wie hier zB

 let zahl1 = Zahlen{
        eins: 14,
        zwei: 2,
        drei: 3,
        vier: 4,
    };

Wenn nun zB nur die "eins" geändert werden soll, wäre es doch blöd, immer wieder alles schreiben zu müssen. Dafür gibt es eine einfache Lösung. Den Doppelpunkt. Nein, nicht diesen : Doppelpunkt, sondern diesen .. Doppelpunkt.

let zahl2 = Zahlen{
        eins: 17,
        ..zahl1
    };

So sieht das dann aus. zahl2 übernimmt ab der zweiten Zahl die Werte von Zahl1. Die Ausgabe entspricht auch wirklich den Erwartungen.

image.png

Für Werte die mit Strings zu tun haben, muss man etwas mehr in die Trickkiste greifen. Es sieht dann so aus.

let car3 = Car{
        farbe:String::from("grün"),
        name:car2.name.clone(),
        modell:car2.modell.clone(),
        ..car2
        
    };

Nur die Farbe ist neu, der Rest bleibt der gleiche Dacia.

image.png

Es gibt eine Zusammenführung der Werte, die dem des Aufrufs in der println! entsprechen. Und hintennach kommt bei allen Stringwerten noch ein .clone() hinzu.

Arbeiten mit externen Funktionen zu Strukturen
Manchmal ist es bestimmt praktisch, Teile einer Struktur in einer Funktion einzubauen. Ein passables Beispiel ist wohl die lange println! Ausgabe nicht immer von vorne formulieren zu müssen. Eigentlich ist es auch gar nicht so schwierig

fn zeige_auto(car:&Car){
    println!("Zeige Auto\nName: {}\nModell:{}\nBaujahr:{}\nPS:{}\nFarbe:{}\n", car.name, car.modell, car.baujahr, car.ps, car.farbe);
}

Man sieht hier, dass der Parameter car auf die Struktur Car zeigt. Neben den üblichen println!-Anweisungen holt sich car die Elemente von Car, genau wie in den Beispielen vorhin mit einem Punkt-Operator.

Ausgabe
image.png

Weiteres zu Strukturen, wenn ich selbst mehr weiß. Aber die Basis ist sicher hier drin.

Zum Schluss wie immer eine Zusammenfassung:

//Structs

struct Zahlen{
    eins: u8,
    zwei: u8,
    drei: u8,
    vier: u8,
}


struct Car{
    farbe: String,
    name: String,
    modell: String,
    baujahr: i32,
    ps:i16,
}

fn zeige_auto(car:&Car){
    println!("Zeige Auto\nName: {}\nModell:{}\nBaujahr:{}\nPS:{}\nFarbe:{}\n", car.name, car.modell, car.baujahr, car.ps, car.farbe);
}

fn main (){

    let car1 = Car{
        farbe: String::from("blau"),
        name:String::from("Opel"),
        modell:String::from("Vectra"),
        baujahr:1992,
        ps:75,
    };
    let mut car2 = Car{
        farbe:String::from("silber/schwarz"),
        name:String::from("Daca"),
        modell:String::from("Logan"),
        baujahr:2006,
        ps:87,
    };

    println!("Name:{}\nModell:{}\nBaujahr:{}\nPS:{}\n",car1.name, car1.modell, car1.baujahr, car1.ps);
    println!("Name:{}\nModell:{}\nBaujahr:{}\nPS:{}\n",car2.name, car2.modell, car2.baujahr, car2.ps);

    car2.name = String::from("Dacia");
    car2.baujahr = 2009;
    println!("Name:{}\nModell:{}\nBaujahr:{}\nPS:{}\n",car2.name, car2.modell, car2.baujahr, car2.ps);



    let zahl1 = Zahlen{
        eins: 14,
        zwei: 2,
        drei: 3,
        vier: 4,
    };
    let zahl2 = Zahlen{
        eins: 17,
        ..zahl1
    };

    println!("zahl1: eins: {}\nzwei: {}\ndrei: {}\nvier: {}\n", zahl1.eins, zahl1.zwei, zahl1.drei, zahl1.vier);
    println!("zahl2: eins: {}\nzwei: {}\ndrei: {}\nvier: {}\n", zahl2.eins, zahl2.zwei, zahl2.drei, zahl2.vier);

     let car3 = Car{
        farbe:String::from("grün"),
        name:car2.name.clone(),
        modell:car2.modell.clone(),
        ..car2
        // baujahr: car2.baujahr,
        // ps: car2.ps,
    };

    println!("Farbe:{}\nName: {}\nModell:{}\nBaujahr:{}\nPS:{}\n",car3.farbe, car3.name, car3.modell, car3.baujahr, car3.ps);
    zeige_auto(&car3);

}

Vom Editor

22-0.png