Die Desugared-Version unterscheidet sich geringfügig von Ihrer Version. Die Linie
v[v[1]] = 999;
eigentlich Desugars zu
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
Dies führt zu derselben Fehlermeldung, aber die Anmerkungen geben einen Hinweis darauf, was passiert:
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
Der wichtige Unterschied zu Ihrer Desugared-Version ist die Bewertungsreihenfolge. Die Argumente eines Funktionsaufrufs werden von links nach rechts in der angegebenen Reihenfolge ausgewertet, bevor der Funktionsaufruf tatsächlich ausgeführt wird. In diesem Fall bedeutet dies, dass zunächst &mut v
eine stimmbare Ausleihe ausgewertet wird v
. Als nächstes Index::index(&v, 1)
sollte ausgewertet werden, aber dies ist nicht möglich - v
ist bereits veränderlich ausgeliehen. Schließlich zeigt der Compiler, dass die veränderbare Referenz für den Funktionsaufruf noch benötigt wird index_mut()
, sodass die veränderbare Referenz noch aktiv ist, wenn versucht wird, die gemeinsam genutzte Referenz aufzurufen .
Die tatsächlich kompilierte Version hat eine etwas andere Auswertungsreihenfolge.
*v.index_mut(*v.index(1)) = 999;
Zunächst werden die Funktionsargumente für die Methodenaufrufe von links nach rechts *v.index(1)
ausgewertet , dh zuerst ausgewertet. Dies führt zu einem usize
, und das temporäre gemeinsame Ausleihen von v
kann wieder freigegeben werden. Dann wird der Empfänger von index_mut()
ausgewertet, dh v
veränderlich ausgeliehen. Dies funktioniert einwandfrei, da der gemeinsame Kredit bereits abgeschlossen wurde und der gesamte Ausdruck den Kreditprüfer besteht.
Beachten Sie, dass die kompilierte Version dies erst seit Einführung der "nicht-lexikalischen Lebensdauer" tut. In früheren Versionen von Rust blieb die gemeinsame Ausleihe bis zum Ende des Ausdrucks bestehen und führte zu einem ähnlichen Fehler.
Die meiner Meinung nach sauberste Lösung ist die Verwendung einer temporären Variablen:
let i = v[1];
v[i] = 999;