How to "branch" out an Iterator

In my mind Iterator contains a state about something and the state can be stored and return to previous state when needed. However it seems like it's not the case in Rust.

I am quite new to Rust (about 4 months of studying), and is doing a project on my own. Then I encounter such problem. For example,

let v = [1, 2, 3, 4, 5];

let mut i1 = v.iter();
println!("{}", i1.next().unwrap()); // Some(1)

// Then I wish to branch out the i1 into another iterator
let mut i2 = i1.branch(); // of course this method doesn't exist

println!("{}", i2.next().unwrap()); // 2
println!("{}", i2.next().unwrap()); // 3

println!("{}", i1.next().unwrap()); // 2

maybe, I don't know for sure, that i2 must be dropped before i1 can be used again, and it is acceptable in my problem. For example

fn print_next_2(iter: Box<dyn Iterator<Item = &'_ i32> + '_>)
    -> Box<dyn Iterator<Item = &'_ i32> + '_>
{
    println!("{}", iter.next().unwrap());
    println!("{}", iter.next().unwrap());

    Box::new(iter)
}

fn main() {
    let v = [1, 2, 3, 4, 5];
    let mut iter = v.iter();
    print_next_2(Box::new(iter.branch())); // 1 2
    // here the iter in the `fn print_next_2` should be dropped already
    
    println!("{}", iter.next().unwrap()); // 1
}

I know there must be some problem with the lifetime specifier, but this should explain what I mean. Thanks very much for any help!

You can .clone() many iterators. Iterator::cycle() method relies on it.

let v = [1, 2, 3, 4, 5];

let mut i1 = v.iter();
println!("{}", i1.next().unwrap()); // Some(1)

let mut i2 = i1.clone();

println!("{}", i2.next().unwrap()); // 2
println!("{}", i2.next().unwrap()); // 3

println!("{}", i1.next().unwrap()); // 2
3 Likes

Some iterators can be cloned, which seems to be the branch() you wished for. Playground.

As for your second question, there may be an X-Y problem here, but just taking a stab at your code directly...

-fn print_next_2(iter: Box<dyn Iterator<Item = &'_ i32> + '_>)
-    -> Box<dyn Iterator<Item = &'_ i32> + '_>
+ // return value removed because you didn't use it
+ // `mut` qualifier added as per compiler suggestion
+fn print_next_2(mut iter: Box<dyn Iterator<Item = &'_ i32> + '_>)
 {
     println!("{}", iter.next().unwrap());
     println!("{}", iter.next().unwrap());
-
-    Box::new(iter)
+    // Side note: `iter` was already in a `Box`, so
+    // you really just wanted `iter` here not `Box::new(iter)`
 }
 
 fn main() {
     let v = [1, 2, 3, 4, 5];
     let mut iter = v.iter();
-    print_next_2(Box::new(iter.branch())); // 1 2
+    print_next_2(Box::new(iter.clone())); // 1 2
     // here the iter in the `fn print_next_2` should be dropped already
    
     println!("{}", iter.next().unwrap()); // 1
 }

Playground.

If you do need to use the iterator and then return the same one, you can, but the lifetimes will need to match up. That (and perhaps the extra Box::new) were what your lifetime errors were about. However, I would instead just change the signature like so, to more directly convey that function uses the iterator but that same iterator will still be available after the call.

1 Like

Note that this is not true for any iterator. For example, if iterator returns non-clonable owned items, this will be impossible.

2 Likes

Why is it impossible? Can't an iterator just store an index on the vec and increment it every time I call next()? In this way the index should be clonable thus the iterator is clonable, even though the vec contains non-clonable items.

That depends on whether the iterator returns references, or returns the items by ownership. With references, no problem. With ownership, it's impossible because ownership can only be given away once.

5 Likes

Thank you very much! Actually I've found this method but not quite work, that might be in my actual code my vec is of non-clonable items. Hopefully #[derive(Clone)] will solve the problem.

Cool, luckily I've written my code as Iterator<Item = &T> and now I have #[derive(Clone)] on T, everything is working great right now. :wink: