Continue iterating a 'moved' iterator

The following code is ilegal because a1 cannot be used a second time:

fn main() {
    let a1 = [1, 2, 3].iter();
    let a2 = [4, 5].iter();
    
    for (x, y) in a1.zip(a2) {
        println!("Paired elements {:?} {:?}", x, y);
    }
    for x in a1 {
        println!("Missing elements {:?}", x);
    }
}

I would like to have a first loop to iterate the paired elements and a second (with different logic) to iterate what is left. Right now I am creating 2 copies of a1, counting the number of paired elements while iterating through the first copy and then skipping that number with the second copy. It is subobtimal. What would be the right way to do it? In a way, I want a Zip that borrows and then gives me back a1.

This sounds like a job for by_ref.

3 Likes

That's funny, because exactly (&mut a1).zip(a2) works.

But you'll find a thing you didn't expect! (Playground link) There are no missing elements.

The reason is that for each iteration, zip will call a1.next(), a2.next(). If one of those is None, it yields None and iteration stops. It will clearly stop here by getting a Some(&3) from a1 and None from a2, so it stops, but not before consuming that last element in a1.

If you look at the Iterator trait you'll see that there is no way to see if the iterator has finished without consuming another element.

2 Likes

Thanks @bluss and &sorear for your answers. As @bluss mentioned, there are no missing elements with either implementation. If let a1 = [1, 2, 3, 4] then I get 4 as missing element, but of course 3 should also be there.

Is there any way of setting things up so that you could start the second iteration at the 3rd element?

Please start a new thread, rather than resurrect a zombie thread from 2016. It's okay to reference the zombie thread, but not to trick URLO readers into thinking that it is somehow current.