Perché più riferimenti mutabili rendono impossibile assegnare a se stesso il membro di una struttura? [duplicare]

Aug 17 2020

Non sono in grado di prendere in prestito dove pensavo di poterlo fare. Ho ridotto il problema a questo caso:

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

Sembra che a.borrowabbia l'intersezione di 'be 'cquindi non può essere garantito che abbia ancora la vita 'c.

Non ho alcun problema reale con questo e posso aggirarlo rendendo entrambe le vite uguali, ma perché questo non prende in prestito l'assegno?


Sembra che le strutture non siano importanti per mostrare questo problema e il doppio prestito lo mostra facilmente.

Ho tre funzioni che sono abbastanza simili, ma avrei problemi a sapere quale compila e quale errore darebbero quelle non compilabili.

La semplice funzione generica:

fn only_borrow<T>(a: &mut T) {
    *a = *a;
}

genera l'errore:

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'inclusione di un livello aggiuntivo di riferimento indiretto modifica l'errore

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

Cambiare le vite implicite può correggere l'errore:

fn working_double<'b, T>(a: &'b mut &'b mut T) {
    *a = *a;
}

Risposte

Emoun Aug 18 2020 at 09:59

Dovrai dare un'occhiata alle tue vite 'be 'c:

  • &'b mut ...significa che hai un riferimento che è vivo e valido per un "tempo" 'b.
  • A<'c>significa che hai un oggetto che è vivo e valido per 'c.

Quello che non hai è una relazione specifica tra queste due vite. L'unica cosa che il compilatore può dedurre è che poiché A<'c>è dietro a &'b, 'cdeve sopravvivere 'b, cioè, ogni volta che 'bè valido, così è 'c. Anche se, soprattutto, non il contrario.

Come mostri, il compilatore richiede 'be 'cche abbia la stessa durata. Perchè è questo?

Diamo uno sguardo alle nostre possibilità:

  1. 'ce 'bnon hanno relazione: è facile vedere che senza alcuna relazione, il compilatore non può garantire nulla su ciò che viene inserito A.borrowe come tale non lo consente.
  2. 'crigorosamente sopravvive 'b, vale a dire, alcuni posti 'cè valido 'bnon lo è:
    a.borrow = a.borrowdiventa una rinascita adell'uso della 'bvita. Questa risposta spiega perché ciò accade . Tuttavia, questo significa che aora dipende dalla 'bdurata, che non è valida per alcune volte aè valida (poiché aha la durata 'c). Questo dà l'errore.
  3. 'brigorosamente sopravvive 'c: se avessimo questa relazione, potrebbe funzionare. Il reborrow sarà valido, poiché otteniamo una durata "maggiore" ( 'b) rispetto a quella richiesta ( 'c). Tuttavia, abbiamo già 'c: 'bdedotto dal compilatore dietro le quinte. Pertanto, aggiungere questa durata significa che le due vite diventano uguali e torniamo al punto di partenza:
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;
}