Reputation: 7927
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?
Upvotes: 3
Views: 2281
Reputation: 36003
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)
}
Upvotes: 3