2014-12-21 7 views
8

voglio scrivere questa struttura:Come scrivere la struttura corretta della durata in Rust?

struct A { 
    b: B, 
    c: C, 
} 

struct B { 
    c: &C, 
} 

struct C; 

Il B.c dovrebbero essere presi in prestito da A.c.

A -> 
    b: B -> 
    c: &C -- borrow from --+ 
          | 
    c: C <------------------+ 

Questo è quello che ho provato:

struct C; 

struct B<'b> { 
    c: &'b C, 
} 


struct A<'a> { 
    b: B<'a>, 
    c: C 
} 

impl<'a> A<'a> { 
    fn new<'a>() -> A<'a> { 
     let c = C; 
     A {c: c, b: B{c: &c}} 
    } 
} 

ma non riesce:

test.rs:17:21: 17:22 error: `c` does not live long enough 
test.rs:17   A {b: B{c: &c}, c: &c} 
          ^
test.rs:15:27: 18:6 note: reference must be valid for the lifetime 'a as defined on the block at 15:26... 
test.rs:15  fn new<'a>() -> A<'a> { 
test.rs:16   let c = C; 
test.rs:17   A {b: B{c: &c}, c: &c} 
test.rs:18  } 
test.rs:15:27: 18:6 note: ...but borrowed value is only valid for the block at 15:26 
test.rs:15  fn new<'a>() -> A<'a> { 
test.rs:16   let c = C; 
test.rs:17   A {b: B{c: &c}, c: &c} 
test.rs:18  } 
test.rs:17:29: 17:30 error: `c` does not live long enough 
test.rs:17   A {b: B{c: &c}, c: &c} 
            ^
test.rs:15:27: 18:6 note: reference must be valid for the lifetime 'a as defined on the block at 15:26... 
test.rs:15  fn new<'a>() -> A<'a> { 
test.rs:16   let c = C; 
test.rs:17   A {b: B{c: &c}, c: &c} 
test.rs:18  } 
test.rs:15:27: 18:6 note: ...but borrowed value is only valid for the block at 15:26 
test.rs:15  fn new<'a>() -> A<'a> { 
test.rs:16   let c = C; 
test.rs:17   A {b: B{c: &c}, c: &c} 
test.rs:18  } 
error: aborting due to 2 previous errors 

Ho letto la documentazione Ruggine sulla proprietà, ma io ancora non so come aggiustalo.

Se ci sono articoli utili, fatemi sapere nei commenti.

+0

"è l'errore" non è una spiegazione sufficiente del problema. Se il compilatore restituisce un errore, inseriscilo e comunicaci da quale linea proviene. –

+0

@DavidGrayson grazie, ho pubblicato. –

+0

@geotheory Scusa, il mio inglese è pessimo, ora ho cambiato il titolo. –

risposta

24

In realtà c'è più di un motivo per cui il codice sopra non funziona. Scopriamolo un po 'ed esploriamo alcune opzioni su come risolverlo. Prima di tutto rimuovere il new e provare a costruire un'istanza di A direttamente nel principale, in modo da vedere che la prima parte del problema non ha nulla a che fare con vite:

struct C; 

struct B<'b> { 
    c: &'b C, 
} 

struct A<'a> { 
    b: B<'a>, 
    c: C 
} 

fn main() { 
    // I copied your new directly here 
    let c1 = C; // and renamed c1 so we know what "c" 
       // the errors refer to 
    let _ = A {c: c1, b: B{c: &c1}}; 
} 

questo non funziona con:

error: use of moved value: `c1` 
let _ = A {c: c1, b: B{c: &c1}}; 
         ^
note: `c1` moved here because it has type `C`, which is non-copyable 
let _ = A {c: c1, b: B{c: &c1}}; 
      ^

quello che dice è che se si assegna c1-c, si sposta la sua proprietà a c (cioè non è possibile accedervi più attraverso c1, solo attraverso c). Ciò significa che tutti i riferimenti a c1 non sarebbero più validi. Ma hai un &c1 ancora in ambito (in B), quindi ruggine non ti permette di compilare questo codice.

Il compilatore suggerisce una possibile soluzione nel messaggio di errore quando dice che il tipo C non è copiabile. Se potessi fare una copia di C, il tuo codice sarebbe valido, perché l'assegnazione di c1 a c creerebbe una nuova copia del valore invece di spostare la proprietà della copia originale.

Siamo in grado di provare questo e fare C copiabile, cambiando la sua definizione in questo modo:

#[derive(Copy)] 
struct C; 

Ora il codice di cui sopra opere. Si noti che ciò che @ matthieu-m dice nel suo commento è ancora vero. Non possiamo memorizzare sia il riferimento a un valore sia il valore stesso in B (stiamo memorizzando un riferimento a un valore e una COPIA del valore qui). Non è solo per le strutture, però, è come funziona la proprietà.

Ora, se non si desidera (o non è possibile) rendere C copiabile, è possibile memorizzare i riferimenti sia in A che in B.

struct C; 

struct B<'b> { 
    c: &'b C, 
} 

struct A<'a> { 
    b: B<'a>, 
    c: &'a C // now this is a reference too 
} 

fn main() { 
    let c1 = C; 
    let _ = A {c: &c1, b: B{c: &c1}}; 
} 

Tutto bene allora? Non proprio ... vogliamo ancora spostare la creazione di A in un metodo new. E QUESTO è dove correremo nei guai con le vite. Spostiamo la creazione di A di nuovo in un impl.

impl<'a> A<'a> { 
    fn new() -> A<'a> { 
     let c1 = C; 
     A {c: &c1, b: B{c: &c1}} 
    } 
} 

come anticipato, ecco il nostro errore vita:

error: `c1` does not live long enough 
A {c: &c1, b: B{c: &c1}} 
     ^~ 

questo è perché c1 è distrutto alla fine del metodo new, quindi non possiamo restituire un riferimento ad esso.

{   
    let c1 = C; // we create c1 here 
    A {c: &c1, b: B{c: &c1}} // ...take a reference to it 
} // and destroy c1 here (so we can't return A with a reference to c1) 

Una possibile soluzione a questo è di creare C all'esterno di new e passarlo come parametro. codice completo qui:

struct C; 

struct B<'b> { 
    c: &'b C, 
} 

struct A<'a> { 
    b: B<'a>, 
    c: &'a C 
} 

fn main() { 
    let c1 = C; 
    let _ = A::new(&c1); 
} 

impl<'a> A<'a> { 
    fn new(c: &'a C) -> A<'a> { 
     A {c: c, b: B{c: c}} 
    } 
} 

playpen

3

Dopo aver controllato con Manishearth e eddyb sul #rust IRC, credo che non sia possibile per una struttura memorizzare un riferimento a se stesso o una parte di sé. Quindi quello che stai cercando di fare non è possibile all'interno del sistema di tipi di Rust.