Returning a higher-kinded closure that captures a borrowed value

Hi, I've run into a bit of a lifetime pickle - first up, here's some (slightly contrived-looking, but representative) code:

struct Opaque(usize);

struct MyStruct<'a>(Vec<&'a Opaque>);

impl<'a> MyStruct<'a> {
    pub fn get_func_for_index(
        &'a self,
        n: usize,
    ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
        let opaque: &'a Opaque = *self.0.get(n)?;

        Some(move |i: &[u8]| &i[opaque.0..])
    }
}

fn main() {
    let o1 = Opaque(1);
    let o5 = Opaque(5);
    let o7 = Opaque(7);

    let x = MyStruct(vec![&o1, &o5, &o7]);

    let drop_five = x.get_func_for_index(1 /*Opaque(5)*/).unwrap();

    let data: Vec<u8> = Vec::from(&b"testing"[..]);

    assert_eq!(drop_five(&data[..]), b"ng");
}

And here's the error (rustc 1.54.0 (a178d0322 2021-07-26)):

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> /tmp/lifetimes.rs:13:31
   |
13 |         Some(move |i: &[u8]| &i[opaque.0..])
   |                               ^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 13:14...
  --> /tmp/lifetimes.rs:13:14
   |
13 |         Some(move |i: &[u8]| &i[opaque.0..])
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> /tmp/lifetimes.rs:13:31
   |
13 |         Some(move |i: &[u8]| &i[opaque.0..])
   |                               ^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 6:6...
  --> /tmp/lifetimes.rs:6:6
   |
6  | impl<'a> MyStruct<'a> {
   |      ^^
note: ...so that return value is valid for the call
  --> /tmp/lifetimes.rs:10:17
   |
10 |     ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: higher-ranked subtype error
  --> /tmp/lifetimes.rs:7:5
   |
7  | /     pub fn get_func_for_index(
8  | |         &'a self,
9  | |         n: usize,
10 | |     ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
   | |_______________________________________________________________________^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.

What I'm trying to do is to return a function/closure from get_func_for_index that in itself is valid for 'a (because it captures &'a self), but can receive a byte slice of any lifetime 'inner as its argument. I think the signature of get_func_for_index should already reflect that, but somehow the lifetimes don't add up.

Is there any way to change this code to do what I want, or is this just not a supported contraption at the moment?

You need to use the "funneling trick" (basically, you can't name higher order lifetimes inside a closure definition, hence the workaround):

fn funnel<F> (f: F)
  -> F
where
    // desired higher-order signature
    F : for<'inner> Fn(&'inner [u8]) -> &'inner [u8],
{
    f
}

And from there, rather than using a literal move |…| … closure, you use it but wrapped within an invocation of funnel:

- Some(       move |i: &[u8]| &i[opaque.0..] )
+ Some(funnel(move |i: &[u8]| &i[opaque.0..]))
7 Likes

Heh, I crossposted it on StackOverflow and got the same answer: rust - Returning a higher-kinded closure that captures a reference - Stack Overflow

The trick to helping the type inference out is to pass the closure through a type-annotated identity function, which forces it to be a HKT.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.