Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `&` needed to destructure a list of tuples during iteration?

Tags:

rust

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 ?

like image 932
Byron Avatar asked Feb 09 '15 08:02

Byron


1 Answers

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 in unsafe blocks to make it work. Containers may also provide into_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.

like image 86
DK. Avatar answered Oct 18 '22 17:10

DK.