Semantics for iterator lifetime for locally defined functions


#1

Hi all

Why are the the semantics different in the following cases?

Why does this code work?

fn find_ramp_items<'a>(entries: &'a HashMap<String, pdl::PdlEntry>) -> impl Iterator<Item = &String> + 'a {
    entries.iter().filter_map(|(_, entry)| match entry {
        pdl::PdlEntry::STR(value) if value.starts_with("RAMPITEMWRAP_") => Some(value),
        _ => None,
    })
}
fn foo(v: &HashMap<String, pdl::PdlEntry>) {
     let ramp_items = find_ramp_items(&v);
}

but this local definition version doesn’t

fn foo( v: &HashMap<String, pdl::PdlEntry>) {
let find_ramp_items = |entries: &HashMap<String, pdl::PdlEntry>| {
     entries.iter().filter_map(|(_, entry)| match entry {
         pdl::PdlEntry::STR(value) if value.starts_with("RAMPITEMWRAP_") => Some(value),
         _ => None,
     })
 };
  let ramp_items = find_ramp_items(&v);
}

with error:-

error: free region `` does not outlive free region `'_#1r`
   --> src\reflection.rs:282:9
    |
282 |         entries.iter().filter_map(|(_, entry)| match entry {
    |         ^^^^^^^^^^^^^^^^^^^

Why the difference in semantics? And is there a way to coerce it to behave the same?


#2

You can try let find_ramp_items = |entries: &'a HashMap<String, pdl::PdlEntry>| (i.e. carry the 'a lifetime to the closure param).

Alternatively, capture v in the closure directly.


#3

Thank you. I didn’t know you could specify a lifetime within a local function - it’s nowhere in the docs!


#4

You can’t declare a generic lifetime parameter in a closure, but you can use lifetime params in scope, like 'a. But personally I’d just capture v in the closure and skip the argument unless you plan on using it across multiple HashMaps.