Perché più riferimenti mutabili rendono impossibile assegnare a se stesso il membro di una struttura? [duplicare]
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.borrow
abbia l'intersezione di 'b
e 'c
quindi 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
Dovrai dare un'occhiata alle tue vite 'b
e '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
, 'c
deve sopravvivere 'b
, cioè, ogni volta che 'b
è valido, così è 'c
. Anche se, soprattutto, non il contrario.
Come mostri, il compilatore richiede 'b
e 'c
che abbia la stessa durata. Perchè è questo?
Diamo uno sguardo alle nostre possibilità:
'c
e'b
non hanno relazione: è facile vedere che senza alcuna relazione, il compilatore non può garantire nulla su ciò che viene inseritoA.borrow
e come tale non lo consente.'c
rigorosamente sopravvive'b
, vale a dire, alcuni posti'c
è valido'b
non lo è:
a.borrow = a.borrow
diventa una rinascitaa
dell'uso della'b
vita. Questa risposta spiega perché ciò accade . Tuttavia, questo significa chea
ora dipende dalla'b
durata, che non è valida per alcune voltea
è valida (poichéa
ha la durata'c
). Questo dà l'errore.'b
rigorosamente 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: 'b
dedotto 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;
}