4

I want to get a function to accept two Iterators and a callback and process as follows:

fn for_xy<I: Iterator<Item = usize>, F>(ix: I, iy: I, f: F) where I: Iterator<Item = usize>, F: FnMut(usize, usize) -> (), { for x in ix { for y in iy { f(x, y); } } } 

but I get this error:

error[E0382]: use of moved value: `iy` --> src/lib.rs:7:18 | 1 | fn for_xy<I: Iterator<Item = usize>, F>(ix: I, iy: I, f: F) | -- move occurs because `iy` has type `I`, which does not implement the `Copy` trait ... 7 | for y in iy { | ^^ `iy` moved due to this implicit call to `.into_iter()`, in previous iteration of loop | note: this function takes ownership of the receiver `self`, which moves `iy` help: consider borrowing to avoid moving into the for loop | 7 | for y in &iy { | ^^^ help: consider further restricting this bound | 3 | I: Iterator<Item = usize> + Copy, | ^^^^^^ 

How can I correct this program?

7
  • 1
    An iterator can be iterated only once. Your code iterates iy many times, once for each item in ix. I suggest accepting slices instead of iterators, since they can be iterated over many times Commented Mar 27, 2021 at 9:54
  • 1
    Another way might be to require Iterator<item = &usize> and use iy.copied(). Commented Mar 27, 2021 at 11:21
  • 1
    If your iterator is Copy, you might be able to solve it by demanding I: Copy. Commented Mar 27, 2021 at 13:16
  • 4
    You can request the iterator to be Clone - many iterators (including those that iterate over Vecs) are. Commented Mar 27, 2021 at 14:08
  • 5
    Requesting Clone (and iterating over iy.clone()) is better than Copy, because more types implement Clone. One such type is std::ops::Range which seems a likely candidate to be passed to a function like this. Commented Mar 27, 2021 at 14:11

1 Answer 1

3

When you run a for loop, the iterable argument you pass is moved into the for loop; after iteration completes, the iterator is dropped. If you want to make the iterator reusable, the typical way is to add a Clone bound. Additionally, in principle you're going to have the same problem (in reverse) with you x items from the ix iterator: because you're reusing them with each iteration of the iy loop, you need to ensure they can be cloned or copied. This problem doesn't happen with usize, which is copyable, but a more generic version will need to include a Clone or Copy bound on ix::Item:

fn for_xy<X, Y, F>(ix: X, iy: Y, f: F) where X: Iterator, X::Item: Clone, Y: Iterator + Clone, F: FnMut(X::Item, Y::Item) ) -> { for x in ix { for y in iy.clone() { f(x.clone(), y) } } } 

In practice, most iterators you encounter in Rust are cheaply cloneable. The colletion iterators (such as Vec::iter, HashMap::iter) contain simple references to the underlying collection, and most iterator adapters (map, filter, etc) are cheaply cloneable so long as the iterator being adapted is as well.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.