Editor's note: The code in this question predates Rust 1.0. Since then, semantics have changed and some of the assertions made in the question are no longer true.
I have the following piece of code:
extern crate debug;
use std::mem::size_of_val;
struct A<'a> {
a: &'a [i64],
}
fn main() {
// code
}
When I define a slice with &
(i.e. &[1, 2, 3]
) as in the following println!
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
the output is
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
Defining a slice without &
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
gives me the same result
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
If I first try to bind an instance of a struct A
, whose a
field is initialized with a reference to a slice (i.e. using &
), to a variable x
let x = A { a: &[1, 2, 3] }; // &[1, 2, 3] is a reference to a slice
and I try to execute a similar println!
as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
However, if I bind an instance of A
, whose a
field is initialized to a slice (not a reference to a slice using &
), to a variable x
let x = A { a: [1, 2, 3] };
and I try to execute a similar println!
as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get the following build error:
/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
I was expecting that only the A { a: &[1, 2, 3] }
definition was allowed because A.a
should have &[i64]
type, but, apparently, Rust allows us to not include an &
symbol.
What is the difference between A { a: &[1, 2, 3] }
and A { a: [1, 2, 3] }
? Why are we allowed to use A { a: [1, 2, 3] }
(in the second example above)?
First, you can use a [T,..n]
where a &[T]
is expected, the conversion to a slice is implicit. So following code is perfectly valid:
let a = [1u, 2, 3];
let b: &[uint] = a;
Your situation is a purely lifetime problem. Your struct is
struct A<'a> {
a: &'a [i64],
}
It holds a slice. A slice is nothing more than a reference to the first element and a count of the number of elements. That's why size_of_val()
called on a A
will always return 16: it's the size of a slice, one u64 for the pointer, and one u64 for the number of elements (as you seems to be on a 64bits computer).
So in your code, the struct does not own the array. The difference in behavior you observe is due to the difference about when the array does out of scope.
First case:
let x = A { a: [1, 2, 3] };
Here you define an array, and stores a slice to this array in your struct. Then when reaching the ;
, your array does out of scope and is destroyed, and thus the reference in x
is not valid anymore: it is forbidden by the compiler.
Second case:
let x = A { a: &[1, 2, 3] };
It is more peculiar. Your array is stored in an anonymous variable. In fact, writing
let foo = &42u;
is equivalent to writing
let _anonymousvariable = 42u;
let foo = &_anonymousvariable;
Except that you can't reach _anonymousvariable
directly.
It's exactly the same for you, your code is equivalent to
let _anonymous_array = [1, 2, 3]
let x = A { a: &_anonymous_array };
and thus is perfectly valid.
Last case:
When you write everything directly in the println!()
. Thanks to previous case, we now see why this works:
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
but in this case there is no problem either:
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
because your arrays only go out of scope when reaching the ;
, and no reference to them exist past this point, so they can be safely deleted and the compiler is happy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With