2014-10-17 9 views
5

Mam następujący fragment kodu:„pożyczył wartość nie żył wystarczająco długo”

extern crate debug; 

use std::mem::size_of_val; 

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

fn main() { 
    // code 
} 

Kiedy zdefiniować plaster z & (tj &[1, 2, 3]) jak w poniższym println!

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

wyjście

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

D efining plaster bez &

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

daje mi sam wynik

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

Jeśli pierwszej próbie wiązania instancję struktury A, którego a pole jest inicjowane z odniesieniem do plasterka (tj stosując &) do zmiennej x

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

i próbuję wykonać podobną println! jak poprzednie

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

dostaję

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

Jednak jeśli wiążę instancję z A, którego pole a jest inicjowane do plasterka (nie jest odniesieniem do plasterka przy użyciu &), do zmiennej x

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

i próbuję wykonać podobną println! jak poprzednie

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

pojawia się następujący błąd kompilacji:

/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 

się spodziewałem że dozwolona jest tylko definicja A { a: &[1, 2, 3] }, ponieważ A.a powinna mieć typ &[i64], ale najwyraźniej Rust pozwala nam nie zawierać symbolu &.

Jaka jest różnica między A { a: &[1, 2, 3] } i A { a: [1, 2, 3] }? Dlaczego możemy używać A { a: [1, 2, 3] } (w drugim przykładzie powyżej)?

Odpowiedz

5

Po pierwsze, można użyć [T,..n], gdzie oczekiwany jest &[T], konwersja do plasterka jest niejawna. Tak więc poniższy kod jest całkowicie ważny:

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

Twoja sytuacja jest problemem czysto życiowym. Twój struct jest

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

Posiada ona kawałek.Plasterek to nic innego jak odniesienie do pierwszego elementu i liczba elementów. Dlatego size_of_val() wywołany na A zawsze zwróci 16: jest to rozmiar plasterka, jeden u64 dla wskaźnika i jeden u64 dla liczby elementów (jak się wydaje na komputerze 64-bitowym).

W kodzie, , struktura nie jest właścicielem tablicy. Różnica w zachowaniu, którą zaobserwujesz, wynika z różnicy, kiedy macierz wykracza poza zakres.

Pierwszy przypadek:

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

Tutaj można zdefiniować tablicę i przechowuje kawałek do tej tablicy w swojej struktury. Następnie, po osiągnięciu ;, twoja macierz wykracza poza zakres i jest niszczona, a zatem odniesienie w x jest już nieważne: jest zabronione przez kompilator.

Druga sprawa:

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

Jest bardziej osobliwe. Twoja tablica jest przechowywana w anonimowej zmiennej. W rzeczywistości, pisanie

let foo = &42u; 

jest równoważne formie pisemnej

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

wyjątkiem, że nie można osiągnąć _anonymousvariable bezpośrednio.

To dokładnie to samo dla ciebie, twój kod jest równoważne

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

a więc jest całkowicie poprawny.

Ostatni przypadek:

Kiedy piszesz wszystko bezpośrednio w println!(). Dzięki poprzednim przypadku, możemy teraz zrozumieć, dlaczego to działa:

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

ale w tym przypadku nie ma też problemu:

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

bo twoi tablice przejść tylko z zakresu po osiągnięciu ; i żadne odniesienie do nich nie istnieje poza tym punktem, więc można je bezpiecznie usunąć i kompilator jest szczęśliwy.

Powiązane problemy