1

I want to transform this function to operate on an iterable container of i32:

fn double_positives0<'a>(numbers: &'a Vec<i32>) -> impl Iterator<Item = i32> + 'a {
    numbers.iter().filter(|x| x > &&0).map(|x| x * 2)
}

I made a too-generic form:

fn double_positives1<T>(
    numbers: T,
    min: T::Item,
    v: T::Item,
) -> impl Iterator<Item = <T::Item as std::ops::Mul<T::Item>>::Output>
where
    T: IntoIterator,
    T::Item: PartialOrd,
    T::Item: Mul<T::Item>,
    T::Item: Copy,
{
    numbers
        .into_iter()
        .filter(move |x| x > &min)
        .map(move |x| x * v)
}

I wasn't able to write a function

  • Which uses reference input (as in double_positives0)
  • Restricted to T::Item of type i32 (this could simplify where)

Something like

fn double_positives2<'a, T>(numbers: &'a T, min: i32, v: i32) -> impl Iterator<Item = i32> + 'a
where
    T: IntoIterator,
    T::Item: I32,
{
    unimplemented!()
}

Rust playground with the previous code samples

How can I do this?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Pascal H.
  • 1,431
  • 8
  • 18
  • It's hard to answer multiple questions made in one post. Please separate them into multiple questions so that we can help you better and so that your questions will help others in the future that have one of the same questions as you! – Shepmaster May 12 '20 at 15:22
  • It looks like your question might be answered by the answers of [Matching a generic parameter to an associated type in an impl](https://stackoverflow.com/q/29345708/155423); [Why does the argument for the find closure need two ampersands?](https://stackoverflow.com/q/33971087/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster May 12 '20 at 15:23
  • *which uses reference input* — **why** would you want this? It's strictly less useful. – Shepmaster May 12 '20 at 15:27
  • 1
    Meanwhile, while I was working on macros!, and I discovered than `T: IntoIterator` is exactly what I need to constrain the `Item` type to be `i32`. @Shepmaster: Your first link [Matching a generic parameter to an associated type in an impl](https://stackoverflow.com/questions/29345708/matching-a-generic-parameter-to-an-associated-type-in-an-impl) is perfect answer. Thank you! – Pascal H. May 12 '20 at 15:49
  • About the reference input on container `number`, I don't want to leave the ownership of my container (to reuse it later). By the way, using the constraint `T: IntoIterator`, now it is simple to express the correct lifetime for the container and the output. I my previous `double_positives1`, I was not able to put `a to the right place (just ``` + `a``` failed) – Pascal H. May 12 '20 at 15:54
  • 1
    *I don't want to leave the ownership of my container* — you [don't have to](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7db209a7323246bd105c3c2746fbcaf7). – Shepmaster May 12 '20 at 16:22

1 Answers1

2

I tried to simplify your generic version as much as possible while staying as close as possible to the semantics of the original non-generic version:

fn double_positives1<'a, T>(
    numbers: &'a mut T,
    min: i32,
    v: i32,
) -> impl Iterator<Item = i32> + 'a
where
    T: Iterator<Item = &'a i32>,
{
    numbers
        .filter(move |&&x| x > min)
        .map(move |&x| x * v)
}

playground

The function takes a reference to an iterator of &i32s and returns an iterator of i32s, same as the original function.

Update: without taking a &mut T

fn double_positives1<'a, T>(
    numbers: T,
    min: i32,
    v: i32,
) -> impl Iterator<Item = i32> + 'a
where
    T: Iterator<Item = &'a i32> + 'a,
{
    numbers
        .filter(move |&&x| x > min)
        .map(move |&x| x * v)
}

playground

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
  • Why `&mut`? There's no need for mutability here. – Shepmaster May 12 '20 at 16:23
  • @pretzelhammer I test your code without mutability (I removed all `mut`), and surprisingly it does not compile anymore. Is it possible to borrow the container as *read only* ? (to avoid to lock it). – Pascal H. May 12 '20 at 16:27
  • To be more precise, there's no need to iterate over mutable values. The iterator itself needs to be mutable in order to update it's own state, but that doesn't need to be exposed outside of this function. – Shepmaster May 12 '20 at 16:57
  • I originally had `&mut T` because I figured the iterator would have to be mutable in order to update its internal state. If I tried just `&T` the compiler would throw `cannot move out of *numbers which is behind a shared reference`. I updated it to use just `T` where `T` is an `iterator` that returns `&i32`s so it would be hard to accidentally "pass ownership" of some collection of `i32`s to the function with `into_iter`, which is what I believe @PascalH. wants to avoid: passing ownership or cloning the collection. – pretzelhammer May 12 '20 at 18:26