La ruggine prende in prestito un comportamento strano
Come il codice ruggine qui sotto: il while
ciclo si compila e funziona bene, ma la for iter
versione non si compila, a causa di un errore:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:22:9
|
20 | for i in v.iter() {
| --------
| |
| immutable borrow occurs here
| immutable borrow later used here
21 | println!("v[i]: {}", i);
22 | v.push(20);
| ^^^^^^^^^^ mutable borrow occurs here
error: aborting due to previous error
Ma come inteso, while
anche il ciclo ha lo stesso scenario len
e get
prende in prestito immutabilmente, perché non è in conflitto con push
il prestito in modo mutevole? Per favore, avvisa qual è la mia comprensione che manca qui, grazie mille per l'illuminazione!
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
v.push(4);
let mut i = 0;
while i < v.len() && i < 10 {
v.push(20);
println!("v[i]: {:?}", v.get(i));
i += 1;
}
// for i in v.iter() {
// println!("v[i]: {}", i);
// v.push(20);
// }
}
Risposte
La for
versione del codice è più o meno equivalente alla seguente:
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
v.push(4);
let mut it = v.iter();
while let Some(i) = it.next() {
println!("v[i]: {}", i);
v.push(20);
}
}
Terreno di gioco
Se provi a compilarlo, otterrai un errore che forse ha un po 'più senso:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:11:9
|
8 | let mut it = v.iter();
| - immutable borrow occurs here
9 | while let Some(i) = it.next() {
| -- immutable borrow later used here
10 | println!("v[i]: {}", i);
11 | v.push(20);
| ^^^^^^^^^^ mutable borrow occurs here
L'iteratore prende in prestito v
immutabilmente per l'intera durata del ciclo, quindi non è possibile prendere in prestito mutabili all'interno del ciclo.
Ovviamente, anche se potessi farlo, finiresti con un ciclo infinito perché continui ad aggiungere un altro elemento.
In poche parole, quando chiami .iter()
, crei un nuovo oggetto (un iteratore), che prende in prestito il tuo vettore (immutabilmente), e dà gli elementi uno per uno, il che significa che in realtà prendi in prestito v
l' intero tempo del ciclo . D'altra parte, quando si accede tramite .get(i)
si prende in prestito direttamente un elemento alla volta dal vettore, e quindi è liberato dalle restrizioni di prestito quando si push
.
La ragione di tale restrizione è molto semplice: immagina che il tuo for
ciclo effettivo sia stato compilato, verrebbe eseguito per sempre (e per evitare questo nel while
ciclo, devi aggiungere la condizione artificiale i<10
!), Mentre questo chiaramente non è l'obiettivo prefissato (o se saresti chiaramente che lo faresti altrimenti, ad esempio con una dichiarazione while let
o loop
), e Rust cerca di impedirti di "spararti a una gamba" perché non sai davvero come fare quello che vuoi fare, e provi il torto modo.
Per fare quello che volevi fare, potresti fare:
for i in 0..v.len() {
v.push(20)
}
perché la v.len()
chiamata non prende v
in prestito per il tempo dell'intero for
ciclo, ma solo all'inizio.