2014-10-17 5 views
5

나는 다음과 같은 코드 조각이 :"빌린 값은 충분히 살지 않는"

extern crate debug; 

use std::mem::size_of_val; 

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

fn main() { 
    // code 
} 

내가 가진 슬라이스를 정의 할 때 & (즉 &[1, 2, 3]을)를 println!을 다음과 같이

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

출력은

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

D &

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

않고 ​​슬라이스 일단의 것은 저 동일한 결과

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

제공 처음 a 필드 슬라이스에 대한 참조로 초기화 구조체 A의 인스턴스를 결합하려고하는 경우 (즉, 변수 x

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

에) &를 사용하고 난 인스턴스를 결합하면 나는, 그러나

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

을 얻을

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

이전의 것들과 유사한 println!를 실행하려고 Aa 필드가 슬라이스로 초기화됩니다 (을 사용하는 슬라이스에 대한 참조가 아닙니다). 26,593,210), 내가

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

내가 다음 빌드 오류 얻을 이전의 것들과 유사한 println! 실행하려고하고 변수 x

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

에 :

/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 

내가 기대되었다 A.a&[i64] 유형을 가져야하므로 A { a: &[1, 2, 3] } 정의 만 허용되었지만, 녹이면 & 기호를 포함 할 수 없습니다.

A { a: &[1, 2, 3] }A { a: [1, 2, 3] }의 차이점은 무엇입니까? 왜 위의 두 번째 예에서 A { a: [1, 2, 3] }을 사용할 수 있습니까?

답변

5

먼저 [T,..n]을 사용할 수 있습니다. 여기에서 &[T]이 예상되는 경우 슬라이스로의 변환은 암시 적입니다. 따라서 다음 코드는 완벽하게 유효합니다.

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

상황은 순전히 평생의 문제입니다. 귀하의 구조체 그것은 슬라이스을 보유하고

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

입니다.슬라이스는 첫 번째 요소에 대한 참조 및 요소 수의 계산에 불과합니다. 따라서 A에서 호출되는 size_of_val()은 항상 16을 반환합니다 : 슬라이스 크기, 포인터에 대한 u64 및 요소 수에 대한 u64 (64 비트 컴퓨터에있는 것처럼)가 반환되는 이유입니다.

코드에서 구조체는 배열을 소유하지 않습니다. 관찰되는 동작의 차이는 어레이가 범위를 벗어나는 경우의 차이 때문입니다.

첫 번째 경우 : 여기

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

당신이 배열을 정의하고 구조체에서이 배열에 조각을 저장합니다. 그런 다음 ;에 도달하면 어레이가 범위를 벗어나서 파괴되므로 x의 참조가 더 이상 유효하지 않습니다. 이는 컴파일러가 금지합니다.

두 번째 경우 :

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

그것은 더 특이한입니다. 배열은 익명 변수에 저장됩니다. 사실,

let foo = &42u; 

를 작성하면 직접 _anonymousvariable에 도달 할 수 있다는 점을 제외하고

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

를 작성하는 것과 동일합니다. 그것은 바로 당신을 위해 동일합니다

, 당신의 코드는

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

에 해당하므로 완벽하게 유효합니다.

마지막 경우 :

당신이 println!()에서 직접 모든 물품.

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

을하지만,이 경우 문제 중 하나가 없다 : 앞의 경우 덕분에, 우리는 지금이 왜 작동하는지 볼 수있는 ;에 도달 할 때 배열 만 범위를 벗어나 이동하기 때문에

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

하고, 이 시점 이후에는 그곳에 대한 참조가 존재하지 않으므로 안전하게 삭제할 수 있고 컴파일러는 행복합니다.

관련 문제