2

Silly n00b trying to learn a bit about Rust. Here is my program:

fn main() {
    let v = vec![1, 2, 3];
    println!("{:?}", v);
    println!("{:?}", &v);
}

Produced the output:

[1, 2, 3]
[1, 2, 3]

What is the point of the &? I was half expecting it to print a memory address.

I was originally thrown by this in the intro where it looks like they are looping through a reference. My guess is that Rust does some magic and detects it is a memory address of a vector?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
speg
  • 1,959
  • 6
  • 24
  • 34

2 Answers2

7

What is the point of the &?

The & takes the reference of an object, as you surmised. However, there's a Debug implementation for references to Debug types that just prints out the referred-to object. This is done because Rust tends to prefer value equality over reference equality:

impl<'a, T: ?Sized + $tr> $tr for &'a T {
    fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) }
}

If you'd like to print the memory address, you can use {:p}:

let v = vec![1,2,3];
println!("{:p}", &v);

it looks like they are looping through a reference

The for i in foo syntax sugar calls into_iterator on foo, and there's an implementation of IntoIterator for &Vec that returns an iterator of references to items in the iterator:

fn into_iter(self) -> slice::Iter<'a, T> {
    self.iter()
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks. I read the section on iterators and saw that the `for i in &v` is giving me i as a reference to each element of v. The for loop is doing the magic of figuring out I want references to each element of the iterable – as opposed to trying to iterate through a pointer. Is that correct? – speg Apr 17 '15 at 18:01
  • @speg I added a part about that. Basically, `for i in foo` uses `IntoIterator`, and there's an implementation of that trait for `&Vec` that delegates to `Vec::iter`. `Vec::iter` returns an iterator that yields references to each item in the vector. – Shepmaster Apr 17 '15 at 18:09
1

The magic is AFAIK in the formatter rather than the compiler. See for example:

fn take_val<T>(a:Vec<T> ) {}
fn take_ref<T>(b:&Vec<T>) {}

fn main() {
    let v = vec![1, 2, 3];
    take_val(&v);
    take_ref(&v);

}

Fails with following error:

<anon>:6:14: 6:16 error: mismatched types:
 expected `collections::vec::Vec<_>`,
    found `&collections::vec::Vec<_>`
(expected struct `collections::vec::Vec`,
    found &-ptr) [E0308]
<anon>:6     take_val(&v);

Which suggests this is due to formatter not wanting to show difference between a reference and a value. In older versions of Rust a &v would have been shown as &[1, 2, 3], if my memory serves me correct.

& has special meaning in Rust. It's not just a reference, it's a note that the value is borrowed to one or more functions/methods.

Daniel Fath
  • 16,453
  • 7
  • 47
  • 82