How to create a closure that returns a slice of a &str

I don't understand why this cannot compile. Everything seems good.

fn main(){
    let len = 10;
    |string: &str| -> &str {&string[0..len]};
}

The output is here.

error: lifetime may not live long enough
 --> src/main.rs:3:29
  |
3 |     |string: &str| -> &str {&string[0..len]};
  |              -        -     ^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
  |              |        |
  |              |        let's call the lifetime of this reference `'2`
  |              let's call the lifetime of this reference `'1`

How can I let the compiler knows lifetime '1 is equivalent to '2? Thanks.

Probably not enough type annotations for inference to kick in, and/or borrowing len is problematic (it is borrowed because it doesn't need to be moved, as usize: Copy).

Providing an explicit type for the whole function and creating a move closure solves the problem.

1 Like

I think it was the type annotation impl FnMut(&str) -> &str took the effect.
This code still cannot compile.
In practice, this closure is not alone in one function. I'm afraid I cannot use type annotation.

fn make_slicer(len: usize) {
    move |string: &str| &string[0..len];
}

With inference not working, you need to explicitly annotate the lifetimes. But this is not possible for closures in stable Rust. In nightly with an unstable feature you can have:

#![feature(closure_lifetime_binder)]

fn main(){
    let len = 10;
    for<'a> |string: &'a str| -> &'a str {&string[0..len]};
}
1 Like

Thanks but this requires nightly toolchain. Is there any other workaround?

This is exactly what I was gonna type, though I will add here, in case they don't know, you can still use normal function to do this,

fn get_substr<'a>(string: &'a str, len: usize) -> &'a str {
      &string[0..len]
}

The way to write the correct lifetime dependency in the closure’s type signature on stable rust is by passing it through some helper function with an appropriate Fn* trait bound.

fn main() {
    let len = 10;
    
    fn with_desired_signature<F: Fn(&str) -> &str>(f: F) -> F {
        f
    }
    with_desired_signature(|string| &string[0..len]);
}
3 Likes

Why don't you explicitly annotate the type using a separate function as I suggested? That doesn't require nightly.

I don't understand why it is a problem that the closure is not "alone". Just wrap it in a function like I provided in the playground, call that function, assign its return value to a variable, and you'll be able to use that variable as if it were assigned the closure directly.

1 Like

Because in practice, the function may look like:

fn main() {
  // many variables
  outer_function(|a: &SomeStruct| ...); 
}

It requires many variables, and it is in a macro call. In comparison, I prefer @steffahn 's.
Thank you all the same.

Thanks a lot.
Most of the time, it is you who solved my problem. :pray:

Well, that's a different scenario, then. In a function signature, type annotations are obligatory, so this works as-is:

fn higher_order<F>(mut slicer: F)
where
    F: FnMut(&str) -> &str
{
    let s = "some string";
    let result = slicer(s);
}
1 Like

Yes, it is. Well, actually when you first proposed your workaround, I was aware that type annotation cannot be avoided. These two workaround both revolve around type annotation, the difference is just a form, isn't it?

Right, what I'm saying is that in this case, wrapping a closure in an fn that simply returns it is not necessary.

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.