When iterating a list of tuples, the &
is needed to make it work. Thus this will work ...
for &(a, b, c) in [("hello", 1.0, 5), ("world", 2.0, 2)].iter() {
println!("{} {} {}", a, b, c);
}
but that won't ...
for (a, b, c) in [("hello", 1.0, 5), ("world", 2.0, 2)].iter() {
println!("{} {} {}", a, b, c);
}
// type mismatch resolving `<core::slice::Iter<'_, (&str, _, _)> as core::iter::Iterator>::Item == (_, _, _)`:
// expected &-ptr,
found tuple [E0271]
I am sure it has to do with intricacies of the destructuring syntax that I have not yet fully internalised.
Can you explain which syntactical truth is behind the ampersand ?
It's because the iter
method for an array [T]
returns an iterator that yields &T
values. That's why the compiler says "expected &-ptr, found tuple [E0271]
".
So why's that? Well, in general, you can't copy T
. Unless the code assumes a more restrictive bound of T: Copy
or T: Clone
, it can only move values of type T
.
This is a problem for arrays because there's no way to move a single element out of an array; doing so would invalidate the whole thing.
Aside:
Vec
and co. get around this by implementing additional logic inunsafe
blocks to make it work. Containers may also provideinto_iter
which gives you an iterator that incrementally consumes the container, allowing you to move values out.
Because you want the array iter
method to work for all arrays, it instead yields immutable references to each element in turn.
As a result, you're trying to destructure a &(&str, f32, i32)
, not a (&str, f32, i32)
, hence the additional &
. Rust doesn't like implicitness, so you have to explicitly destructure the reference. This also helps make it clear that there's a dereference and a copy happening here.
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