fn main() {
let v = vec![1, 2, 3, 4, 5];
let a: &i32 = &v[1];
let b: i32 = v[1];
println!("The second element is {}", a);
println!("The second element is {}", b);
}
Why both prints are equals, but variable 'a' has symbol '&' near i32 and near v[1] ? And why are these symbols (&) needed in this case?
The variable a has type &i32 which is a “reference to a 32-bit signed integer”
while variable b has type i32 which is a “32-bit signed integer”.
The & sign here—in the type—means “reference to”. The & sign in the expression&v[1] means “create a reference pointing to”. The expression v[1] denotes the second element od the vector v. Assigning it to b just copies the integer value out of the array, whereas creating a reference pointing to v[1] and assigning that reference to a internally just calculates the memory address of the integer inside of the vector.
let v = vec![1, 2, 3, 4, 5];
// create a reference pointing/referring to the second element of the vector `v`
let a: &i32 = &v[1];
// `a: &i32` means:
// “a is a reference to a 32-bit signed integer”
// create a copy of the second element of the vector `v`
let b: i32 = v[1];
// `b: i32` means:
// “b is a 32-bit signed integer”
Regarding printing, the println macro prints a reference to some type the same way it prints the type itself. The printing logic (for {} formatting) operates using the Display trait, which is implemented for reference types (here) by just ignoring the extra indirection, so you will not get any visible difference in the print-out.
The programming language Rust in general tries to make the difference between a type, say Foo, and the “type of references to Foo”, that is: &Foo, behave as similar as possible in situations where the difference doesn’t matter too much. For example you can call methods on an x: Foo by writing x.some_method() as well as you can call the same method on a y: &Foo as x.some_method(). [Of course there is a difference between i32 and &i32 and there are also (lots of) situations where that difference matters.]
I almost didn't understand anything, but thank you so much for this huge answer. I read chapter 4, but i don't understand why type annotation has symbol '&'. Thank u.
Yeah, I guess chapter 4 of the book doesn’t necessarily do the best job of introducing the concept of references without prior knowledge on e.g. pointers in C.
I’m looking if I find better introductory material somewhere.
I mean, it has to do with whether you make a copy of the data in the vector, or if you just remember where in the vector the element is. There's not much point in using a reference in this case, because copying an integer is incredibly cheap, but if the vector contained elements that are expensive clone, it could be a lot cheaper to just keep a reference to the element than to make a clone of it.
Of course, making a reference requires that the vector stays valid, since the data is still stored in the vector. E.g. this doesn't compile:
// does not compile
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
let a: &i32 = &v[1];
v.clear();
println!("The second element is {}", a);
}
But the above would compile if you instead took a copy of the integer, since clearing the vector doesn't destroy the copy.