Pourquoi plusieurs références mutables rendent-elles impossible l'attribution du membre d'une structure à lui-même? [dupliquer]
Je ne peux pas emprunter là où je pensais pouvoir le faire. J'ai réduit le problème à ce cas:
struct A<'a> {
borrow: &'a mut u8,
}
fn does_nothing<'b, 'c>(a: &'b mut A<'c>) {
a.borrow = a.borrow;
}
error[E0623]: lifetime mismatch
--> src/lib.rs:6:16
|
5 | fn does_nothing<'b, 'c>(a: &'b mut A<'c>) {
| -------------
| |
| these two types are declared with different lifetimes...
6 | a.borrow = a.borrow;
| ^^^^^^^^ ...but data from `a` flows into `a` here
Il semble qu'il a.borrow
a l'intersection de 'b
et 'c
ne peut donc pas être garanti d'avoir encore la durée de vie 'c
.
Je n'ai aucun problème réel avec cela et je peux contourner le problème en rendant les deux durées de vie identiques, mais pourquoi cela n'emprunte pas de chèque?
Il semble que les structures ne sont pas importantes pour montrer ce problème et les doubles emprunts le montrent facilement.
J'ai trois fonctions qui sont assez similaires, mais j'aurais du mal à savoir laquelle compile et quelle erreur les non-compilantes donneraient.
La fonction générique simple:
fn only_borrow<T>(a: &mut T) {
*a = *a;
}
entraîne l'erreur:
error[E0507]: cannot move out of `*a` which is behind a mutable reference
--> src/lib.rs:2:10
|
2 | *a = *a;
| ^^ move occurs because `*a` has type `T`, which does not implement the `Copy` trait
L'inclusion d'un niveau supplémentaire d'indirection change l'erreur
fn only_borrow_double<T>(a: &mut &mut T) {
*a = *a;
}
error[E0623]: lifetime mismatch
--> src/lib.rs:2:10
|
1 | fn only_borrow_double<T>(a: &mut &mut T) {
| -----------
| |
| these two types are declared with different lifetimes...
2 | *a = *a;
| ^^ ...but data from `a` flows into `a` here
S'éloigner des durées de vie implicites peut corriger l'erreur:
fn working_double<'b, T>(a: &'b mut &'b mut T) {
*a = *a;
}
Réponses
Vous devrez jeter un œil à votre vie 'b
et 'c
:
&'b mut ...
signifie que vous avez une référence qui est en direct et valide pour un «temps»'b
.A<'c>
signifie que vous avez un objet vivant et valable pour'c
.
Ce que vous n'avez pas, c'est une relation spécifique entre ces deux vies. La seule chose que le compilateur peut déduire est que puisque se A<'c>
trouve derrière a &'b
, 'c
doit survivre 'b
, c'est- à -dire que chaque fois que 'b
est valide, il en est de même 'c
. Bien que, surtout, pas l'inverse.
Comme vous le montrez, le compilateur requiert 'b
et 'c
doit avoir la même durée de vie. Pourquoi est-ce?
Jetons un coup d'œil à nos possibilités:
'c
et'b
n'ont pas de relation: il est facile de voir que sans aucune relation, le compilateur ne peut rien garantir sur ce qui est misA.borrow
et ne le permettra pas.'c
survit strictement'b
, c'est-à-dire que certains endroits'c
est valide'b
n'est pas:
a.borrow = a.borrow
devient un réemprunt de l'a
utilisation de la'b
durée de vie. Cette réponse explique pourquoi cela se produit . Cependant, cela signifie quea
dépend maintenant de la'b
durée de vie, qui n'est pas valide pendant une partie du tempsa
est valide (depuisa
la durée de vie'c
). Cela donne l'erreur.'b
survit strictement'c
: si nous avions cette relation, cela pourrait fonctionner. Le reborrow sera valide, car nous obtenons une durée de vie "plus grande" ('b
) que celle demandée ('c
). Cependant, nous avons déjà'c: 'b
déduit par le compilateur dans les coulisses. Par conséquent, ajouter cette durée de vie signifie que les deux durées de vie deviennent égales et nous sommes alors de retour au point de départ:
struct A<'a> {
borrow: &'a mut u8,
}
/// We add the relation 'b: 'c
fn does_nothing<'b: 'c, 'c>(a: &'b mut A<'c>) {
a.borrow = a.borrow;
}