Zum Inhalt springen

Borrowing

fn incr(n: &mut i32) {
*n += 1;
}
fn main() {
let mut n = 1;
incr(&n);
println!("{n}");
}

Obwohl n als mut markiert ist, muss die Referenz auf n ebenfalls als mut markiert werden. Eine gültige Version dieses Programms würde also incr(&mut n) lauten.


fn main() {
let mut s = String::from("hello");
let s2 = &s;
let s3 = &mut s;
s3.push_str(" world");
println!("{s2}");
}

Es ist unzulässig, eine mutable Referenz auf einen Wert (s3) zu verwenden, während eine immutable Referenz (s2) noch aktiv ist.


Betrachten Sie diese Rust-Funktion, die eine Zahl an das Ende eines Vektors anhängt und dann die Zahl vom Anfang des Vektors entfernt und zurückgibt:

fn give_and_take(v: &Vec<i32>, n: i32) -> i32 {
v.push(n);
v.remove(0)
}

Normalerweise, wenn Sie versuchen, diese Funktion zu kompilieren, gibt der Compiler den folgenden Fehler zurück:

error[E0596]: cannot borrow `*v` as mutable, as it is behind a `&` reference
--> test.rs:2:5
|
1 | fn give_and_take(v: &Vec<i32>, n: i32) -> i32 {
| --------- help: consider changing this to be a mutable reference: `&mut Vec<i32>`
2 | v.push(n);
| ^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Nehmen Sie an, dass der Compiler diese Funktion NICHT abgelehnt hat. Wählen Sie jedes (falls zutreffend) der folgenden Programme aus, das bei Ausführung möglicherweise undefiniertes Verhalten verursachen könnte. Wenn keines dieser Programme undefiniertes Verhalten verursachen könnte, dann wählen Sie “Keines dieser Programme”.

Wie wir bereits in diesem Abschnitt gesehen haben, kann v.push(n) dazu führen, dass v seinen internen Inhalt neu zuweist, wodurch alle Referenzen auf die Elemente von v auf dem Heap ungültig werden. Daher führt der Aufruf von give_and_take(&v, 4) dazu, dass zuvor erstellte Elementreferenzen auf ungültigen Speicher zeigen. Die beiden Programme, die let n = &v[0] vor give_and_take binden, sind Kandidaten für undefiniertes Verhalten. let v2 = &v ist kein Kandidat, da eine Referenz auf den Container v durch die Mutation von v nicht tatsächlich ungültig wird.

Das Programm, das println!("{}", n) ausführt, verursacht undefiniertes Verhalten durch das Lesen des ungültigen Speichers. Das Programm, das println!("{}", k) ausführt, verursacht kein undefiniertes Verhalten, da es die ungültige Referenz nicht verwendet.