Einführung
Einzelne Variablen reichen für kleine Beispiele aus. In echten Programmen müssen jedoch häufig zusammengehörige Daten in einem Wert gebündelt werden. Ein Rust-Struct definiert die Form dieses Datensatzes. Ein impl-Block stellt die Operationen bereit, die zu diesem Datensatz gehören.
Sie vervollständigen ein vorbereitetes Modell InventoryItem in vier kleinen Änderungen: Sie definieren die Felder, erstellen ein gültiges Element, berechnen über &self den Bestandswert und aktualisieren über &mut self die Menge. Das fertige Programm weist sowohl den gespeicherten Zustand als auch das Verhalten der Methoden nach.
Inventardatensatz definieren
In diesem Schritt definieren Sie die drei Datenbestandteile, die zu einem Inventarelement gehören.
Wechseln Sie in das vorbereitete Cargo-Projekt und öffnen Sie die Quelldatei:
cd /home/labex/project/inventory-item
nano src/main.rs
Die Deklaration struct InventoryItem { ... } führt einen neuen Datensatztyp ein. Innerhalb der geschweiften Klammern steht für jedes Feld zuerst der Name, gefolgt von einem Doppelpunkt und dem Typ. Jeder Wert vom Typ InventoryItem muss alle diese Felder bereitstellen.
Ersetzen Sie den Kommentar für Schritt 1 durch diese drei Feldzeilen:
name: String,
price_cents: u32,
quantity: u32,
name enthält eigenen Text, während die beiden u32-Felder nichtnegative ganze Zahlen speichern. Die abschließenden Kommas trennen die Felder und erleichtern es, später Zeilen hinzuzufügen oder neu anzuordnen.
Speichern Sie mit Ctrl+O, drücken Sie die Enter-Taste und beenden Sie den Editor mit Ctrl+X. Lassen Sie Cargo die Typdefinitionen prüfen:
cargo check
Ein Ergebnis mit Finished und ohne Warnungen bedeutet, dass die Form des Structs gültig ist und jeder vorbereitete Wert eindeutig verwendet wird. Der Konstruktor enthält weiterhin todo!, eine vorübergehende Markierung für noch nicht fertigen Code. Rust erlaubt diese Markierung während cargo check. Beim Ausführen eines Programmablaufs, der todo! erreicht, würde das Programm jedoch mit einer Panik abbrechen. Im nächsten Schritt ersetzen Sie diese Markierung, bevor Sie das Programm ausführen.
Ein vollständiges Element erstellen
In diesem Schritt wandeln Sie die zugehörige Funktion new in einen Konstruktor um, der ein vollständiges InventoryItem zurückgibt.
Der Block impl InventoryItem fasst Operationen für diesen Typ zusammen. new ist eine zugehörige Funktion, weil sie kein self empfängt. Sie wird über den Typ mit InventoryItem::new(...) aufgerufen. Eine Methode wie value_cents empfängt self und wird über einen Wert mit item.value_cents() aufgerufen. Der Rückgabetyp Self ist innerhalb dieses impl-Blocks eine andere Bezeichnung für InventoryItem.
Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie innerhalb von new die gesamte Zeile mit todo!(...) durch:
Self { name, price_cents, quantity }
Dies ist ein Struct-Ausdruck. Durch die Feld-Kurzschreibweise von Rust steht name für name: name, wenn Parameter und Feld denselben Namen haben. Der Ausdruck endet nicht mit einem Semikolon, weil er der von der Funktion zurückgegebene Wert ist.
Speichern und beenden Sie den Editor. Prüfen und starten Sie anschließend das Programm:
cargo check
cargo run --quiet
Die aktuelle Ausgabe sollte folgendermaßen aussehen:
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 0 cents
Adding 3 units
Quantity after restock: 4
Final value: 0 cents
Das Element existiert nun mit den übergebenen Feldwerten. Die Nullen und die unveränderte Menge stammen von den beiden noch vorhandenen Platzhaltern in den Methoden und sind in diesem Schritt daher zu erwarten.
Wert mit &self berechnen
In diesem Schritt vervollständigen Sie eine Methode, die zwei Felder liest, ohne den Besitz zu übernehmen oder das Element zu verändern.
Der Parameter &self ist eine gemeinsam genutzte Referenz auf das aktuelle InventoryItem. Er ist eine Kurzschreibweise für einen geliehenen Wert mit dem konkreten Typ &InventoryItem. Beim Aufruf von item.value_cents() wird dieser Parameter automatisch an die Methode übergeben.
Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie innerhalb von value_cents nur den Platzhalter 0 durch:
self.price_cents * self.quantity
Mit dem Punktoperator wählen Sie Felder des geliehenen Elements aus. Die Multiplikation ergibt den Gesamtwert in Cent. Da kein abschließendes Semikolon vorhanden ist, wird dieser Ausdruck zum von der Methode zurückgegebenen u32-Wert.
Speichern und beenden Sie den Editor. Führen Sie anschließend das Programm aus:
cargo run --quiet
Die Wertzeilen sollten nun folgendermaßen lauten:
Starting value: 1000 cents
...
Final value: 1000 cents
Vier Einheiten zu je 250 Cent ergeben 1000 Cent. Beide Zeilen stimmen weiterhin überein, weil restock die Menge noch nicht geändert hat. Diese kontrollierte Änderung folgt im letzten Schritt.
Bestand mit &mut self auffüllen
In diesem Schritt vervollständigen Sie eine Methode, die über einen exklusiven geliehenen Zugriff ein Feld verändert.
Der Empfänger &mut self ist eine veränderbare Referenz auf das aktuelle Element. Dadurch kann die Methode Felder aktualisieren, ohne den Besitz zu übernehmen. Die Bindung in main wurde bereits mit let mut item deklariert und kann daher diesen vorübergehend veränderbaren Zugriff bereitstellen.
Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie den Kommentar für Schritt 4 innerhalb von restock durch:
self.quantity += amount;
Der Operator += addiert den Wert auf der rechten Seite zum vorhandenen Feld und speichert das Ergebnis wieder in diesem Feld. Dies ist eine Anweisung und endet daher mit einem Semikolon.
Speichern und beenden Sie den Editor. Prüfen und starten Sie anschließend das fertige Modell:
cargo check
cargo run --quiet
Die vollständige Ausgabe sollte folgendermaßen aussehen:
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 1000 cents
Adding 3 units
Quantity after restock: 7
Final value: 1750 cents
Die Menge steigt von vier auf sieben. Dieselbe Methode value_cents liest anschließend den neuen Zustand. Die veränderbare Ausleihe endet nach restock, sodass der folgende Code das Element wieder normal lesen kann.
Zusammenfassung
Sie haben ein Struct definiert, das zusammengehörige Felder bündelt, Werte über einen Self-Konstruktor erstellt, den Zustand mit einer &self-Methode gelesen und den Zustand mit einer &mut self-Methode aktualisiert. Die abschließende Inventarausgabe hat gezeigt, dass Erstellung, Berechnung und Änderung zusammen funktionieren.


