Einführung
Beim Verschieben eines String wird die Eigentümerschaft übertragen. Viele Funktionen benötigen jedoch nur vorübergehend Zugriff. Rust bezeichnet diesen vorübergehenden Zugriff als Borrow und stellt ihn durch eine Referenz dar.
Sie vervollständigen ein vorbereitetes Programm für eine Gästeliste in drei kleinen Schritten: Sie untersuchen eigenen Text über eine gemeinsam genutzte Referenz, beobachten absichtlich, warum ein gemeinsam genutzter Zugriff keine Änderung erlaubt, und führen anschließend über eine veränderbare Referenz eine kontrollierte Änderung durch. Die abschließende Ausgabe zeigt, dass main die Eigentümerschaft an der Liste weiterhin besitzt und die Liste verwenden kann.
Daten über eine gemeinsam genutzte Referenz untersuchen
In diesem Schritt geben Sie einer Funktion schreibgeschützten Zugriff auf einen String, anstatt die Eigentümerschaft an die Funktion zu übertragen.
Wechseln Sie in das vorbereitete Cargo-Projekt und öffnen Sie den Quellcode:
cd /home/labex/project/guest-borrowing
nano src/main.rs
Die Vorbereitung hat das vollständige Projekt erstellt und beim Aufruf von inspect_guests einen Platzhalter hinterlassen. Der Parametertyp der Funktion ist &String. Das Zeichen & bedeutet „eine Referenz auf einen String“: Die Funktion kann den Wert vorübergehend anzeigen, wird aber nicht zu dessen Besitzer.
Ersetzen Sie nur /* Step 1: borrow guest_list */ durch &guest_list, sodass der Aufruf wie folgt aussieht:
inspect_guests(&guest_list);
&guest_list erstellt hier eine gemeinsam genutzte Referenz. „Gemeinsam genutzt“ bedeutet, dass schreibgeschützter Zugriff geteilt werden kann, ohne den String selbst zu übertragen.
Speichern Sie mit Ctrl+O, drücken Sie Enter und beenden Sie den Editor mit Ctrl+X. Führen Sie das Programm aus:
cargo run --quiet
Die Ausgabe sollte so aussehen:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo
Die erste Zeile stammt aus der ausgeliehenen Referenz. Die zweite Zeile ist der wichtige Nachweis für die Eigentümerschaft: Nachdem inspect_guests zurückgekehrt ist, kann main guest_list weiterhin verwenden. Die Update-Funktion liest ebenfalls den aktuellen Wert, ändert ihn zu diesem Zeitpunkt aber noch nicht.
Die Einschränkung gemeinsam genutzter Referenzen beobachten
In diesem Schritt versuchen Sie absichtlich, den String über eine gemeinsam genutzte Referenz zu ändern. Die fehlgeschlagene Compilerprüfung ist erwartet und liefert Ihnen einen Beleg für die Borrowing-Regel von Rust.
Öffnen Sie den Quellcode erneut:
nano src/main.rs
Entfernen Sie innerhalb von add_guest nur die führenden // aus der vorbereiteten Zeile, sodass sie wie folgt aussieht:
list.push_str(", Mina");
Die Methode push_str hängt Text an einen String an und benötigt daher die Berechtigung, den Wert zu ändern. list hat derzeit jedoch den Typ &String, der gemeinsam genutzten, schreibgeschützten Zugriff gewährt.
Speichern Sie die Datei und beenden Sie den Editor. Überlegen Sie vor der Prüfung, was passieren wird: Der Compiler sollte die versuchte Änderung ablehnen, weil eine gemeinsam genutzte Referenz keinen veränderbaren Zugriff ermöglicht.
Führen Sie die Prüfung aus. Ein Fehler ist hier erwartet:
cargo check
Suchen Sie in der Diagnose nach diesen stabilen Teilen:
error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
...
consider changing this to be a mutable reference
Die Schreibweise *list bezeichnet den String, der über die Referenz erreicht wird. Rust sagt nicht, dass der String grundsätzlich niemals geändert werden kann. Die Meldung bedeutet, dass diese konkrete &String keine Berechtigung zum Ändern überträgt. Im nächsten Schritt gewähren Sie einen kontrollierten veränderbaren Zugriff.
Über eine veränderbare Referenz aktualisieren
In diesem Schritt geben Sie add_guest vorübergehend die exklusive Berechtigung, den String des aufrufenden Codes zu ändern.
Eine veränderbare Referenz hat die Form &mut T. Eine hilfreiche Regel für den Einstieg lautet: Viele Leser oder jeweils ein Schreiber. Gemeinsam genutzte Referenzen erlauben das Lesen, während eine veränderbare Referenz vorübergehend exklusiven Schreibzugriff gewährt. Diese Exklusivität verhindert, dass zwei Teile eines Programms denselben Wert unerwartet ändern.
Öffnen Sie die Datei:
nano src/main.rs
Nehmen Sie drei gezielte Änderungen vor:
- Ändern Sie den Parameter von
add_guestvon&Stringin&mut String. - Fügen Sie der Bindung
muthinzu, sodass sielet mut guest_list = ...lautet. - Ändern Sie den Aufruf von
add_guestvon&guest_listin&mut guest_list.
Die vervollständigte Funktionssignatur und der Aufruf sollten diese Formen haben:
fn add_guest(list: &mut String) {
add_guest(&mut guest_list);
Die beiden Verwendungen von mut hängen zusammen, haben aber unterschiedliche Aufgaben. let mut guest_list bedeutet, dass der eigene Wert geändert werden darf. &mut guest_list erstellt anschließend eine vorübergehende veränderbare Referenz, die add_guest für die Dauer des Aufrufs exklusiven Schreibzugriff leiht.
Speichern Sie die Datei und beenden Sie den Editor. Prüfen Sie anschließend die Korrektur:
cargo check
Ein Ergebnis mit Finished ohne E0596 bedeutet, dass die Berechtigungen jetzt zusammenpassen. Führen Sie das Programm aus:
cargo run --quiet
Die abschließende Ausgabe sollte so aussehen:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo, Mina
Der veränderbare Borrow endet, sobald add_guest zurückkehrt. Die abschließende Ausgabe kann guest_list wieder lesen. Damit ist bewiesen, dass die Eigentümerschaft in main geblieben ist, während die Funktion eine kontrollierte Änderung vorgenommen hat.
Zusammenfassung
Sie haben &String für gemeinsam genutzten, schreibgeschützten Zugriff und &mut String für vorübergehende, exklusive Änderungen verwendet. In beiden Fällen behielt der aufrufende Code die Eigentümerschaft. Der Compiler half dabei, den Unterschied zwischen dem Anzeigen und dem Ändern ausgeliehener Daten durchzusetzen.



