Lektionen des Moduls (2/2)
Referenzen und Borrowing
In Rust kann die ständige Übergabe des Besitzes (Ownership) einer Variablen an eine Funktion und deren Rückgabe sehr umständlich sein. Um dieses Problem zu lösen, verwendet Rust Referenzen (references).
Das Erstellen einer Referenz auf einen Wert wird als Borrowing (Ausleihen) bezeichnet.
Unveränderliche Referenzen
Eine Referenz wird deklariert, indem das Symbol & vor den Typ oder die Variable gestellt wird. Standardmäßig sind Referenzen unveränderlich (immutable): Sie erlauben das Lesen des Wertes, aber nicht dessen Modifikation.
fn main() {
let s1 = String::from("hello");
// Passiamo un riferimento a s1, non l'ownership
let len = calculate_length(&s1);
// s1 è ancora utilizzabile qui!
println!("La lunghezza di '{}' è {}.", s1, len);
}
fn calculate_length(s: &String) -> usize { // s è un riferimento a una String
s.len()
} // Qui s esce dallo scope, ma poichè non possiede il valore, non succede nulla
Veränderliche Referenzen
Wenn Sie einen ausgeliehenen Wert ändern müssen, müssen Sie eine veränderliche Referenz über &mut verwenden. Die ursprüngliche Variable muss ebenfalls als veränderlich mit mut deklariert werden:
fn main() {
let mut s = String::from("hello");
// Passiamo un riferimento mutabile
change(&mut s);
println!("{}", s); // Stampa "hello, world"
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
Die goldenen Regeln des Borrowings
Um Speicherbeschädigungen und Race Conditions (Datenrennen) zur Compilezeit zu verhindern, stellt Rust zwei grundlegende Regeln auf:
- Sie können beliebig viele unveränderliche Referenzen (
&T) auf einen Wert zur gleichen Zeit haben. - ODER Sie können genau eine veränderliche Referenz (
&mut T) auf einen Wert auf einmal haben.
Sie können unveränderliche und veränderliche Referenzen für denselben Wert im selben Gültigkeitsbereich absolut nicht mischen:
let mut s = String::from("hello");
let r1 = &s; // Valido
let r2 = &s; // Valido
// let r3 = &mut s; // ERRORE DI COMPILAZIONE! Non puoi creare &mut s se s è già presa in prestito come immutabile
Der Gültigkeitsbereich von Referenzen und Non-Lexical Lifetimes (NLL)
In der Vergangenheit dauerte der Gültigkeitsbereich einer Referenz zwingend bis zum Ende des Blocks, in dem sie erstellt wurde. Heute ist der Rust-Compiler dank Non-Lexical Lifetimes (NLL) intelligenter: Der Gültigkeitsbereich einer Referenz endet in der letzten Zeile, in der sie verwendet wird, nicht notwendigerweise am Blockende.
Dies macht den folgenden Code gültig:
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} e {}", r1, r2); // Ultimo uso di r1 e r2. I riferimenti immutabili scadono qui!
let r3 = &mut s; // Valido! Nessun riferimento immutabile è attivo a questo punto
Probiere es aus
Übergeben Sie eine unveränderliche Referenz von s1 an die Funktion calculate_length unter Verwendung des Symbols &.
Hinweis anzeigen
Ersetzen Sie `/* TODO \_/`durch`&s1`, um eine unveränderliche Referenz auf den String zu übergeben.
Lösung nach 3 Versuchen verfügbar
Machen Sie die Variable s veränderlich (let mut s) und übergeben Sie eine veränderliche Referenz (&mut s) an die Funktion change, um ihr die Änderung des Strings zu ermöglichen.
Hinweis anzeigen
Verwenden Sie `let mut s`anstelle von`let s`und rufen Sie`change(&mut s);` auf.
Lösung nach 3 Versuchen verfügbar
Deklarieren Sie eine Variable s, die String::from("Rust") enthält. Erstellen Sie zwei verschiedene unveränderliche Referenzen r1 und r2 auf s und geben Sie die beiden Referenzen schließlich durch ein Leerzeichen getrennt mit dem println!-Makro aus.
Hinweis anzeigen
Weisen Sie `let r1 = &s;` und `let r2 = &s;` zu, um zwei unveränderliche Referenzen zu erhalten, und geben Sie sie dann mit `println!("{} {}", r1, r2);` aus.
Lösung nach 3 Versuchen verfügbar