2014-10-17 16 views
5

Ho il seguente pezzo di codice:"Valore preso in prestito non vive abbastanza a lungo" quando si utilizza una struttura con una fetta

extern crate debug; 

use std::mem::size_of_val; 

struct A<'a> { 
    a: &'a [i64], 
} 

fn main() { 
    // code 
} 

Quando mi definisco una fetta con & (cioè &[1, 2, 3]) come nel seguente println!

println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] }); 

l'uscita è

16 - A<'static>{a: &[1i64, 2i64, 3i64]} 

D efining una fetta senza &

println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] }); 

mi dà lo stesso risultato

16 - A<'static>{a: &[1i64, 2i64, 3i64]} 

Se prima tenta di associare l'istanza di una struct A, la cui a campo viene inizializzato con un riferimento a una porzione (cioè utilizzando &), ad una variabile x

let x = A { a: &[1, 2, 3] }; // &[1, 2, 3] is a reference to a slice 

e cerco di eseguire un simile println! come i precedenti

println!("{} - {:?}", size_of_val(&x), x); 

ottengo

16 - A<'static>{a: &[1i64, 2i64, 3i64]} 

Tuttavia, se mi legano un'istanza di A, il cui campo a è inizializzato su una sezione (non un riferimento a una sezione utilizzando &), ad una variabile x

let x = A { a: [1, 2, 3] }; 

e cerco di eseguire un simile println! come i precedenti

println!("{} - {:?}", size_of_val(&x), x); 

ottengo il seguente errore di generazione:

/prpath/main.rs:12:20: 12:29 error: borrowed value does not live long enough 
/prpath/main.rs:12  let x = A { a: [1 ,2, 3] }; 
             ^~~~~~~~~ 
/prpath/main.rs:11:11: 15:2 note: reference must be valid for the block at 11:10... 
/prpath/main.rs:11 fn main() { 
/prpath/main.rs:12  let x = A { a: [1 ,2, 3] }; 
/prpath/main.rs:13 
/prpath/main.rs:14  println!("{} - `{:?}`", size_of_val(&x), x); 
/prpath/main.rs:15 } 
/prpath/main.rs:12:5: 12:31 note: ...but borrowed value is only valid for the statement at 12:4; consider using a `let` binding to increase its lifetime 
/prpath/main.rs:12  let x = A { a: [1 ,2, 3] }; 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

mi aspettavo che solo la definizione A { a: &[1, 2, 3] } era consentita perché A.a dovrebbe avere il tipo &[i64], ma, a quanto pare, Rust ci consente di non includere un simbolo &.

Qual è la differenza tra A { a: &[1, 2, 3] } e A { a: [1, 2, 3] }? Perché siamo autorizzati a utilizzare A { a: [1, 2, 3] } (nel secondo esempio sopra)?

risposta

5

Innanzitutto, è possibile utilizzare uno [T,..n] dove è previsto un &[T], la conversione in una sezione è implicita. Quindi il seguente codice è perfettamente valido:

let a = [1u, 2, 3]; 
let b: &[uint] = a; 

La tua situazione è un problema puramente di durata. La vostra struct è

struct A<'a> { 
    a: &'a [i64], 
} 

Essa detiene una fetta .Una fetta non è altro che un riferimento al primo elemento e un conteggio del numero di elementi. Ecco perché size_of_val() chiamato su A restituisce sempre 16: è la dimensione di una sezione, una di tipo u64 per il puntatore e una di 64 per il numero di elementi (come sembra essere su un computer a 64 bit).

Quindi nel codice, la struttura non possiede l'array. La differenza di comportamento che si osserva è dovuta alla differenza quando l'array fa fuori dall'ambito.

Primo caso:

let x = A { a: [1, 2, 3] }; 

Qui definire un array, e memorizza una fetta di questo array nella vostra struct. Quindi, quando si raggiunge lo ;, l'array viene messo fuori portata e distrutto, pertanto il riferimento in x non è più valido: è vietato dal compilatore.

Secondo caso:

let x = A { a: &[1, 2, 3] }; 

E 'più peculiare. Il tuo array è memorizzato in una variabile anonima. In realtà, la scrittura

let foo = &42u; 

è equivalente a scrivere

let _anonymousvariable = 42u; 
let foo = &_anonymousvariable; 

Solo che non è possibile raggiungere direttamente _anonymousvariable.

E 'esattamente lo stesso per voi, il vostro codice è equivalente a

let _anonymous_array = [1, 2, 3] 
let x = A { a: &_anonymous_array }; 

e quindi è perfettamente valida.

Ultimo caso:

Quando si scrive tutto direttamente nel println!(). Grazie al caso precedente, ora vediamo il motivo per cui questo funziona:

println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] }); 

ma in questo caso non v'è alcun problema:

println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] }); 

perché gli array solo andare fuori portata al raggiungimento della ;, e nessun riferimento a loro esiste oltre questo punto, quindi possono essere tranquillamente cancellati e il compilatore è felice.

Problemi correlati