La versión desugared es ligeramente diferente de la que tienes. La línea
v[v[1]] = 999;
en realidad desugar a
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Esto da como resultado el mismo mensaje de error, pero las anotaciones dan una pista de lo que está sucediendo:
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 diferencia importante con su versión desugared es el orden de evaluación. Los argumentos de una llamada a la función se evalúan de izquierda a derecha en el orden indicado, antes de realizar la llamada a la función. En este caso, esto significa que primero &mut v
se evalúa, pidiendo prestado de forma mutable v
. A continuación, Index::index(&v, 1)
debe evaluarse, pero esto no es posible: v
ya está prestado de manera mutable. Finalmente, el compilador muestra que la referencia mutable todavía es necesaria para la llamada a la función index_mut()
, por lo que la referencia mutable todavía está viva cuando se intenta la referencia compartida.
La versión que realmente compila tiene un orden de evaluación ligeramente diferente.
*v.index_mut(*v.index(1)) = 999;
Primero, los argumentos de la función para las llamadas al método se evalúan de izquierda a derecha, *v.index(1)
es decir, se evalúa primero. Esto da como resultado a usize
, y el préstamo compartido temporal de v
se puede liberar nuevamente. Luego, index_mut()
se evalúa el receptor de , v
es decir, se toma prestado de forma mutable. Esto funciona bien, ya que el préstamo compartido ya se ha finalizado, y toda la expresión pasa el corrector de préstamo.
Tenga en cuenta que la versión que compila solo lo hace desde la introducción de "vidas no léxicas". En versiones anteriores de Rust, el préstamo compartido viviría hasta el final de la expresión y daría lugar a un error similar.
La solución más limpia en mi opinión es usar una variable temporal:
let i = v[1];
v[i] = 999;