1

I have an infinite iterator and I want to print different slices from the iterator.

So, if I call extract(8,&[1,2,3,4]), in console i want to see/get:

1
2 3
4 1 2
3 4 1 2
3 4 1 2 3
4 1 2 3 4 1
2 3 4 1 2 3 4

My attemp:

fn extract(n: usize, seq: &[u16]) {
    let mut iterator = seq.iter().cycle();

    for it in 1..n {
        iterator.take(it).for_each(|x| print!("{} ", x)); // <- Problem is here
        print!("\n");
    }
}

When I compile:

warning: variable does not need to be mutable
 --> src/lib.rs:2:9
  |
2 |     let mut iterator = seq.iter().cycle();
  |         ----^^^^^^^^
  |         |
  |         help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

error[E0382]: use of moved value: `iterator`
 --> src/lib.rs:5:9
  |
2 |     let mut iterator = seq.iter().cycle();
  |         ------------ move occurs because `iterator` has type `std::iter::Cycle<std::slice::Iter<'_, u16>>`, which does not implement the `Copy` trait
...
5 |         iterator.take(it).for_each(|x| println!("{} ", x));
  |         ^^^^^^^^ value moved here, in previous iteration of loop

I understand that iterator changes its value in each loop iteration. That is why I marked as mutated var. But somehow, iterator var is used as argument of a function (which I can't see) and the iterator is moved. So in the next loop iteration, iterator var is out of scope and I get the moved value error.

To understand better my code:

  • Where is my iterator variable moving to?

  • How can I use the iterator inside the loop without this problem?

Community
  • 1
  • 1
jamarier
  • 87
  • 7
  • It's unclear to me exactly _what_ you where trying to do here, so my answer explains why you have an error, but not what you could do to fix it. Had you provided an example with the expected output, I could have provided a solution. – mcarton Jul 21 '20 at 12:24
  • I particular I don't know whether you intend `iterator` to restart at each iteration of the outer loop or to keep it running from wherever it left off. – mcarton Jul 21 '20 at 12:25

2 Answers2

4

As others wrote, take consumes your iterator. To avoid this, you can use by_ref which wraps the original iterator and can be consumed without consuming the original iterator

fn extract(n: usize, seq: &[u16]) {
    let mut iterator = seq.iter().cycle();

    for it in 1..n {
        iterator.by_ref().take(it).for_each(|x| println!("{} ", x));
        print!("\n");
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
phimuemue
  • 34,669
  • 9
  • 84
  • 115
1

If you look at the exact error message:

error[E0382]: use of moved value: `iterator`
 --> src/lib.rs:5:6
  |
2 |   let mut iterator = seq.iter().cycle();
  |       ------------ move occurs because `iterator` has type `std::iter::Cycle<std::slice::Iter<'_, u16>>`, which does not implement the `Copy` trait
...
5 |      iterator.take(it).for_each(|x| println!("{} ", x)); // <- Problem is here
  |      ^^^^^^^^ value moved here, in previous iteration of loop

The compiler underlines where the value is moved, which is in iterator.take(…). Let's have a look at Iterator::take's definition:

fn take(self, n: usize) -> Take<Self>

It takes self by value, that is, to call it, you have to move the instance.

mcarton
  • 27,633
  • 5
  • 85
  • 95
  • 1
    See also [Why does Iterator::take_while take ownership of the iterator?](https://stackoverflow.com/q/31374051/155423) – Shepmaster Jul 21 '20 at 12:34