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 Likes
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);
}
}
5 Likes
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?
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.
3 Likes
I understand now. Thanks!