Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IntoIterator as a function argument doesn't accept adapter struct

Tags:

iterator

rust

I want to have a function, that accepts &IntoIterator<Item=u32>, so I could pass to it both &Vec<u32> and iterators' adapter structs (like Map, Filter and any other, which I believe all implement IntoIterator)

So I have a function like

pub fn f<'a, T>(it_src: &'a T) -> u32
where &'a T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32;
    // more more usage
    result
}

And this is how I tried to use it (same signature, but different name)

pub fn f_with_feature()<'a, T>(it_src: &'a T) -> u32
where &'a T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(&adjusted_values)
}

What I've got is an error

 error[E0308]: mismatched types
  --> src\main.rs:14:7
   |
14 |     f(&adjusted_values)
   |       ^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::iter::Map`
   |
   = note: expected type `&T`
              found type `&std::iter::Map<<&T as std::iter::IntoIterator>::IntoIter, [closure@src\main.rs:13:14: 13:27]>`

How is it that Map doesn't match as T?

Also, I've come up with an idea, that passing iterators' adaptors with static dispatch isn't a good idea since each other closure used to generate a Map will create a new function specialization. Though I've seen that static dispatch approach for most of the times is idiomatic in Rust. How to manage this situation?

like image 678
Alexey Larionov Avatar asked Sep 22 '26 07:09

Alexey Larionov


1 Answers

I think you want to have trait bounds on T (and not on &'a T). So I guess you actually want the following:

pub fn f<'a, T>(it_src: &'a T) -> u32
where T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<'a, T>(it_src: &'a T) -> u32
where T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(&adjusted_values)
}

Which brings us to the next problem: IntoIterator's into_iter consumes self, which means that you cannot call it_src.into_iter if you only borrow it_src.

So if you really want to use into_iter, you can try this:

pub fn f<T>(it_src: T) -> u32
where T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<T>(it_src: T) -> u32
where T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(adjusted_values)
}

The above, however, requires you to move the values into f resp. f_with_feature.

In my experience, just taking an iterator (and doing the conversion at call site if necessary), leads to simple, straightforward solutions:

pub fn f<T>(it_src: T) -> u32
where T: Iterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<T>(it_src: T) -> u32
where T: Iterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(adjusted_values)
}
like image 170
phimuemue Avatar answered Sep 25 '26 01:09

phimuemue



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!