Дезертирована версія трохи відрізняється від тієї, що у вас є. Лінія
v[v[1]] = 999;
насправді desugars до
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Це призводить до того ж повідомлення про помилку, але примітки дають підказку щодо того, що відбувається:
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
Важливою відмінністю вашої зневіреної версії є порядок оцінювання. Аргументи виклику функції оцінюються ліворуч праворуч у вказаному порядку, перш ніж здійснювати виклик функції. У цьому випадку це означає, що спочатку &mut v
оцінюється, неміцно запозичивши v
. Далі Index::index(&v, 1)
слід оцінити, але це неможливо - v
це вже мутантно запозичене. Нарешті, компілятор показує, що змінна посилання все ще потрібна для виклику функції index_mut()
, тому посилання, що змінюється, залишається активною при спробі спільної посилання.
Фактично складена версія має дещо інший порядок оцінювання.
*v.index_mut(*v.index(1)) = 999;
По-перше, аргументи функції для викликів методу оцінюються зліва направо, тобто *v.index(1)
оцінюються спочатку. Це призводить до того usize
, що тимчасові спільні позики v
можуть бути звільнені знову. Потім приймач index_mut()
оцінюється, тобто v
є мутантно запозиченим. Це прекрасно працює, оскільки спільний позик вже завершений, і весь вираз передає позику перевірки.
Зауважимо, що версія, яка складається, робить це лише з моменту введення "нелексичних життєвих ресурсів". У попередніх версіях Руста спільне запозичення збережеться до кінця виразу і призведе до подібної помилки.
Найчистішим рішенням, на мою думку, є використання тимчасової змінної:
let i = v[1];
v[i] = 999;