La versione desugared è leggermente diversa da quella che hai. La linea
v[v[1]] = 999;
in realtà desugars a
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Ciò provoca lo stesso messaggio di errore, ma le annotazioni danno un suggerimento su ciò che sta accadendo:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:7:48
|
7 | *IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
| ------------------- ------ ^^ immutable borrow occurs here
| | |
| | mutable borrow occurs here
| mutable borrow later used by call
La differenza importante con la tua versione desugared è l'ordine di valutazione. Gli argomenti di una chiamata di funzione vengono valutati da sinistra a destra nell'ordine elencato, prima di effettuare effettivamente la chiamata di funzione. In questo caso ciò significa che &mut v
viene valutato per primo , mutuamente mutuato v
. Successivamente, Index::index(&v, 1)
dovrebbe essere valutato, ma questo non è possibile - v
è già mutuamente preso in prestito. Infine, il compilatore mostra che il riferimento mutabile è ancora necessario per la chiamata della funzione index_mut()
, quindi il riferimento mutabile è ancora attivo quando si tenta il riferimento condiviso.
La versione effettivamente compilata ha un ordine di valutazione leggermente diverso.
*v.index_mut(*v.index(1)) = 999;
Innanzitutto, gli argomenti delle funzioni per le chiamate al metodo vengono valutati da sinistra a destra, ovvero *v.index(1)
vengono valutati per primi. Ciò si traduce in un usize
e il prestito condiviso temporaneo di v
può essere rilasciato nuovamente. Quindi, index_mut()
viene valutato il ricevitore di , ovvero v
viene mutuamente mutuato. Funziona bene, poiché il prestito condiviso è già stato finalizzato e l'intera espressione passa il controllo del prestito.
Nota che la versione che compila lo fa solo dopo l'introduzione di "vite non lessicali". Nelle versioni precedenti di Rust, il prestito condiviso sarebbe durato fino alla fine dell'espressione e si sarebbe verificato un errore simile.
La soluzione più pulita secondo me è usare una variabile temporanea:
let i = v[1];
v[i] = 999;