La version désucrée est légèrement différente de ce que vous avez. La ligne
v[v[1]] = 999;
fait desugars à
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Il en résulte le même message d'erreur, mais les annotations donnent une indication sur ce qui se passe:
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 différence importante par rapport à votre version désucrée est l'ordre d'évaluation. Les arguments d'un appel de fonction sont évalués de gauche à droite dans l'ordre indiqué, avant d'effectuer réellement l'appel de fonction. Dans ce cas, cela signifie que le premier &mut v
est évalué, en empruntant mutuellement v
. Ensuite, Index::index(&v, 1)
devrait être évalué, mais ce n'est pas possible - v
est déjà mutuellement emprunté. Enfin, le compilateur montre que la référence mutable est toujours nécessaire pour l'appel de fonction à index_mut()
, de sorte que la référence mutable est toujours active lorsque la référence partagée est tentée.
La version qui compile a un ordre d'évaluation légèrement différent.
*v.index_mut(*v.index(1)) = 999;
Tout d'abord, les arguments de fonction des appels de méthode sont évalués de gauche à droite, c'est *v.index(1)
-à- dire qu'ils sont évalués en premier. Il en résulte un usize
et l'emprunt partagé temporaire de v
peut être à nouveau libéré. Ensuite, le récepteur de index_mut()
est évalué, c'est v
-à- dire qu'il est mutuellement emprunté. Cela fonctionne très bien, car l'emprunt partagé a déjà été finalisé et l'expression entière passe le vérificateur d'emprunt.
Notez que la version qui compile ne le fait que depuis l'introduction des "durées de vie non lexicales". Dans les versions antérieures de Rust, l'emprunt partagé durerait jusqu'à la fin de l'expression et entraînerait une erreur similaire.
La solution la plus propre à mon avis est d'utiliser une variable temporaire:
let i = v[1];
v[i] = 999;