Background
I was trying to make a trait that generalizes iterating through a collection:
trait MakeIter<'a, C, T>
where
C: ?Sized,
T: 'a,
{
type Iter: Iterator<Item = &'a T>;
fn make_iter(&mut self, collection: &'a C) -> Self::Iter;
}
Then, I implement this trait for functions that return iterators:
impl<'a, C, T, F, R> MakeIter<'a, C, T> for F
where
C: 'a + ?Sized,
T: 'a,
F: FnMut(&'a C) -> R,
R: Iterator<Item = &'a T>,
{
type Iter = R;
fn make_iter(&mut self, collection: &'a C) -> Self::Iter {
self(collection)
}
}
To test the trait, I use this function:
fn test_make_iter(mut make_iter: impl for<'a> MakeIter<'a, [i32], i32>) {
let data = [1, 2, 3, 4];
for x in make_iter.make_iter(&data) {
println!("{}", x);
}
}
This works for normal functions:
fn make_iter(slice: &[i32]) -> impl Iterator<Item = &i32> {
slice.iter()
}
test_make_iter(make_iter); // OK.
But not for closures:
test_make_iter(|s: &[i32]| s.iter()); // Error: implementation of `MakeIter` is not general enough.
Unless I use a helper function:
fn infer_helper<F: FnMut(&[i32]) -> std::slice::Iter<i32>>(f: F) -> F {
f
}
test_make_iter(infer_helper(|s: &[i32]| s.iter())); // OK.
The test code can be found here.
Analysis
I am guessing for test_make_iter(|s: &[i32]| s.iter())
, the type of |s: &[i32]| s.iter()
is impl FnMut(&'a [i32]) -> std::slice::Iter<'a, i32>
, where 'a
is some concrete lifetime.
But for test_make_iter(infer_helper(|s: &[i32]| s.iter()))
, the type of |s: &[i32]| s.iter()
is for <'a> impl FnMut(&'a [i32]) -> std::slice::Iter<'a, i32>
, where 'a
may be any lifetime, that is why it works.
Question
If my analysis is correct, why doesn’t Rust infer the type of the closure to the more general one (the for <'a>
version) so I don’t need the helper function? Is this something Rust can improve on?