Wersja wypuszczona różni się nieco od tego, co masz. Linia
v[v[1]] = 999;
w rzeczywistości desugars do
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Powoduje to ten sam komunikat o błędzie, ale adnotacje dają wskazówkę, co się dzieje:
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
Ważną różnicą w stosunku do twojej wersji testowej jest kolejność oceny. Argumenty wywołania funkcji są przetwarzane od lewej do prawej w podanej kolejności, przed wykonaniem wywołania funkcji. W tym przypadku oznacza to, że najpierw &mut v
wycenia się, pożyczając w sposób zmienny v
. Następnie Index::index(&v, 1)
należy ocenić, ale nie jest to możliwe - v
jest już pożyczone w sposób zmienny. Na koniec kompilator pokazuje, że zmienne odwołanie jest nadal potrzebne do wywołania funkcji index_mut()
, więc zmienne odwołanie jest nadal aktywne, gdy podejmowana jest próba udostępnienia odwołania.
Wersja, która faktycznie się kompiluje, ma nieco inną kolejność oceny.
*v.index_mut(*v.index(1)) = 999;
Po pierwsze, argumenty funkcji wywołań metod są oceniane od lewej do prawej, tzn. Są *v.index(1)
oceniane jako pierwsze. Powoduje to usize
, a tymczasowe wspólne pożyczenie v
może zostać ponownie zwolnione. Następnie odbiorca index_mut()
jest oceniany, tj. v
Jest mutycznie pożyczany. Działa to dobrze, ponieważ wspólny kredyt został już sfinalizowany, a całe wyrażenie przechodzi przez moduł sprawdzający pożyczkę.
Zauważ, że wersja, która się kompiluje, robi to tylko od czasu wprowadzenia „nie-leksykalnych żywotności”. We wcześniejszych wersjach Rust wspólna pożyczka istniałaby do końca wyrażenia i powodowała podobny błąd.
Moim zdaniem najczystszym rozwiązaniem jest użycie zmiennej tymczasowej:
let i = v[1];
v[i] = 999;