简体   繁体   中英

Type bound for a function with return lifetime

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)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM