Lifetime error: function vs closure

In a loop I have a line that looks like this:

let toks = HashSet::<&str>::from_iter(s.split(','))};

It's actually a bit more complicated than that and I'm doing the same processing on multiple bits of text, so I decided to clean it up with a closure:

let tokenize = |s: &str| -> HashSet::<&str> { ... };

And I got a lifetime error explaining that the parameter reference must outlive the return value reference. I thought, OK, maybe it's a scoping / borrow issue. But to make sure, I wrote an equivalent function:

fn tokenize(s: &str) -> HashSet::<&str> { ... }

And lo and behold, it compiles just fine, no lifetime error. What gives?

The compiler is bad at inferring when closures have to be higher ranked (take any lifetime and return an input lifetime), and lifetime elision doesn't work the same on annotated closures.

You can give it a hint like so.

(The closure annotation isn't needed given the hint.)

Alternatively, you can use nightly's closure_lifetime_binder feature:

#![feature(closure_lifetime_binder)]

use std::collections::HashSet;

fn main() {
    let _ = for<'a> |s: &'a str| -> HashSet<&'a str> {
        HashSet::from_iter(s.split(','))
    };
}
1 Like