Версия desugared немного отличается от того, что у вас есть. Линия
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
есть заимствован. Это работает нормально, поскольку общий заем уже завершен, и все выражение проходит проверку заимствования.
Обратите внимание, что версия, которая компилируется, делает это только после введения «нелексических времен жизни». В более ранних версиях Rust общее заимствование сохранялось до конца выражения и приводило к аналогичной ошибке.
На мой взгляд, самое чистое решение - использовать временную переменную:
let i = v[1];
v[i] = 999;