Consider the function
fn f(v: &[usize]) -> impl Iterator<Item = usize> + '_ {
v.iter().cloned()
}
I want to write a generic function g which accepts any function with the same signature as f, and calls that function with various lifetimes. Is this possible?
My attempt 1: I naively wrote
fn g<F>(f: F)
where
F: for<'a> Fn(&'a [usize]) -> (impl Iterator<Item = usize> + 'a) {}
but I got
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
My attempt 2: I tried to give g another type parameter for the specific iterator type:
fn g<F, I>(f: F)
where
I: Iterator<Item = usize>,
F: for<'a> Fn(&'a [usize]) -> I {}
I think this would work if the iterator were 'static. But in this case I'd need I to be a higher kinded type with one lifetime parameter. Concretely, this g compiles but doesn't accept f.
My attempt 3: As above, but giving g a lifetime parameter to specialize f:
fn g<'a, F, I>(f: F)
where
I: Iterator<Item = usize> + 'a,
F: Fn(&'a [usize]) -> I {}
This compiles and accepts f, but the body of g can only use f with the specific lifetime 'a.
As Sven Marnach pointed out it could be done with a Box pointer.
fn f(v: &[usize]) -> Box<dyn Iterator<Item = usize> + '_> {
Box::new(v.iter().cloned())
}
fn g<F>(f: F)
where
F: Fn(&[usize]) -> Box<dyn Iterator<Item = usize> + '_>
{
let v = vec![1, 2, 3];
{
let iter = f(&v);
for i in iter {
println!("{}", i);
}
}
}
fn main() {
g(f)
}
Based on this post, I found a solution for the original interface (without a Box) using a helper trait:
fn f(v: &[usize]) -> impl Iterator<Item = usize> + '_ {
v.iter().cloned()
}
trait Helper<'a> {
type I: Iterator<Item = usize> + 'a;
fn call(self, v: &'a [usize]) -> Self::I;
}
impl<'a, I, F> Helper<'a> for F
where
I: Iterator<Item = usize> + 'a,
F: Fn(&'a [usize]) -> I,
{
type I = I;
fn call(self, v: &'a [usize]) -> Self::I {
self(v)
}
}
fn g<F>(f: F)
where
F: for<'a> Helper<'a>,
{
let v = vec![1, 2, 3];
{
let iter = f.call(&v);
for i in iter {
println!("{}", i);
}
}
}
pub fn main() {
g(f)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With