Reference syntax in for-loop iterator


#1

I’m curious why the for-loop iterating syntax leaves out that each element is a reference. That is, why is it this way:

let nums = vec![1, 2, 3];

for num in &nums {
println!("{}", *num);
}

Where &nums says that each of num will be a reference.

vs.

for &num in &nums {
println!("{}", *num);
}

Where it clearly says that num is a reference?
This… has been bothering me a lot


#2

The same reason that a in let a = &value is a reference and b in let &b = &value is a value. The left-hand side of an assignment (or for in expression) is an irrefutable pattern. If you wanted to state that num is a reference, you’d need to use type ascription (currently in-progress but not implemented) and write for (x: &u32) in &nums {} (as you would write let x: TYPE = EXPR;).

In case it helps, here is a more obvious use of patterns in the left-hand side of a for loop expression:

struct Test(u8);

fn main() {
    let nums = vec![Test(1), Test(2), Test(3)];

    for Test(num) in nums {
        println!("{}", num);
    }
}

#3

Thanks for your reply.

In let a = &value, we can clearly tell that &value is a reference (which a will be assigned to).
In for num in &nums, &nums is a reference to some iterable, but it does not say that num will be a reference too – it seems like this is a special rule specifically for these range loops. Shouldn’t we use &num to make it clear that num is a reference?


#4

Again, that won’t work for the reason I stated above. &num is a pattern that destructures the reference and extracts the value. There is no way around this. However, I should note that, by convention, IntoIterator<Item=T> is implemented on Container<T> and IntoIterator<Item=&T> is implemented on &Container<T> so a for loop iterating over an &Container<T> will generally return references and a for loop iterating over a Container<T> will generally return values.

Anyways, while let a = &value; is clearly a reference because you’re explicitly referencing value, you can also write let a = some_fn();. In this case a could be anything. If you want to ensure that it is a reference, you’d have to write let a: &_ = some_fn();. You can’t currently do this in for loops but I believe type ascription will make this possible.


#5

I understand now. Thanks!