Pourquoi plusieurs références mutables rendent-elles impossible l'attribution du membre d'une structure à lui-même? [dupliquer]

Aug 17 2020

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.borrowa l'intersection de 'bet 'cne 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

Emoun Aug 18 2020 at 09:59

Vous devrez jeter un œil à votre vie 'bet '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, 'cdoit survivre 'b, c'est- à -dire que chaque fois que 'best valide, il en est de même 'c. Bien que, surtout, pas l'inverse.

Comme vous le montrez, le compilateur requiert 'bet 'cdoit avoir la même durée de vie. Pourquoi est-ce?

Jetons un coup d'œil à nos possibilités:

  1. 'cet 'bn'ont pas de relation: il est facile de voir que sans aucune relation, le compilateur ne peut rien garantir sur ce qui est mis A.borrowet ne le permettra pas.
  2. 'csurvit strictement 'b, c'est-à-dire que certains endroits 'cest valide 'bn'est pas:
    a.borrow = a.borrowdevient un réemprunt de l' autilisation de la 'bdurée de vie. Cette réponse explique pourquoi cela se produit . Cependant, cela signifie que adépend maintenant de la 'bdurée de vie, qui n'est pas valide pendant une partie du temps aest valide (depuis ala durée de vie 'c). Cela donne l'erreur.
  3. 'bsurvit 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: 'bdé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;
}