1

I have a function that takes a &Vector<T>. I want to change it to take an iterator in order to run it on different container/collection/slice types.

It produces an error because the function is called twice.

What I Have So Far

fn operate_on_iterator<'a>(iterator: &impl IntoIterator<Item = i32>) -> i32 {
    // This is an example. Please don't tell me to use `.sum`.
    let mut sum = 0;
    for val in iterator.into_iter() {
        sum += val;
    }
    sum
}

fn caller() -> i32 {
    let v = vec![1, 2, 3, 4];

    let s1 = operate_on_iterator(&v);
    let s2 = operate_on_iterator(&v);

    s1 + s2
}

playground

The Error I Get

error[E0507]: cannot move out of `*iterator` which is behind a shared reference
  --> src/lib.rs:13:16
   |
13 |     for val in iterator.into_iter() {
   |                ^^^^^^^^ move occurs because `*iterator` has type `impl IntoIterator<Item = i32>`, which does not implement the `Copy` trait

Restrictions and notes

  1. I do not want to use dyn because I prefer the slightly larger code size over the performance impact of pointer dereferencing. (Although I will use it for now and will benchmark it once I have both traits and trait objects implemented, i.e. after I have an answer to this question.) Also using dyn also didn't work so far for me.
  2. I have used this answer as a basis. How to write a Rust function that takes an iterator?
  3. My Item implements Clone, Binding, and Drop.
  4. I also tried to implement it using Iterator instead of IntoIterator. Also no luck.
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Unapiedra
  • 15,037
  • 12
  • 64
  • 93
  • 1
    It looks like your question might be answered by the answers of [Why can't I use `&Iterator` as an iterator?](https://stackoverflow.com/q/51758485/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Nov 16 '20 at 20:13
  • 1
    TL;DR — an **immutable** iterator cannot be mutated, thus it cannot be advanced. – Shepmaster Nov 16 '20 at 20:14
  • You also probably want `impl IntoIterator` or maybe `impl IntoIterator`. See also [How do I create a function that accepts an iterator of i32s as either values or references and sums them?](https://stackoverflow.com/q/46288670/155423); [How to write a Rust function that takes an iterator?](https://stackoverflow.com/q/34969902/155423). – Shepmaster Nov 16 '20 at 20:17
  • Thank you very much, @Shepmaster. This is indeed already answered. Since it took me a while to get the necessary changes from that answer, I've posted what is needed to make it work. However, your link is the answer. – Unapiedra Nov 16 '20 at 20:28
  • 1
    [You could also use `Iterator` directly instead of `IntoIterator`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=be182354f85327cac0022920ed7798db) – Ibraheem Ahmed Nov 16 '20 at 20:30
  • 1
    @IbraheemAhmed it's true, but it's a nicer API to accept `IntoIterator`. That allows more things to be directly passed. – Shepmaster Nov 16 '20 at 20:31

1 Answers1

2

Shepmaster linked to the answer.

For completeness, this is the necessary change:

&impl IntoIterator<Item = i32> --> impl IntoIterator<Item = &'a i32>

Resulting in this code:

fn operate_on_iterator<'a>(iterator: impl IntoIterator<Item = &'a i32>) -> i32 {
    // This is an example. Please don't tell me to use `.sum`.
    let mut sum = 0;
    for val in iterator.into_iter() {
        sum += val;
    }
    sum
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Unapiedra
  • 15,037
  • 12
  • 64
  • 93