1

I've got some trouble with replacing function with equivalent closure, compiler complaining

cannot infer an appropriate lifetime due to conflicting requirements

note: ...so that the types are compatible:
      expected &std::collections::BTreeSet<&str>
         found &std::collections::BTreeSet<&str> rustc(E0495)

in the closure, at the rangemethod in r.extend(s.range(lower..=upper));. But i can't figure out how to put lifetime hint in a closure, and maybe, it's not possible.

use std::collections::BTreeSet;

fn main() {
    let mut set = BTreeSet::new();

    set.insert("TEST1");
    set.insert("TEST3");
    set.insert("TEST4");
    set.insert("TEST2");
    set.insert("TEST5");

    println!("init: {:?}", set);

    let closure = |lower, upper| {        
        |s: &BTreeSet<&str>| {
            let mut r = BTreeSet::new();
            r.extend(s.range(lower..=upper));
            r
        }
    };

    set = extract_fn("TEST2", "TEST5")(&set);
    set = closure("TEST3", "TEST4")(&set);
    println!("result: {:?}", set);
}

fn extract_fn<'a>(
    lower: &'a str,
    upper: &'a str,
) -> impl Fn(&BTreeSet<&'a str>) -> BTreeSet<&'a str> {
    move |s| {
        let mut r = BTreeSet::new();
        r.extend(s.range(lower..=upper));
        r
    }
}

Except putting static lifetime, should a closure with this type of error be transformed to a function ?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Sté
  • 195
  • 11
  • @Shepmaster not sure about duplicate, and IMHO, the answer with `for<>` may be interesting for broad range of lifetime problems. – Sté Feb 25 '19 at 08:28

1 Answers1

1

This cannot be done easily but you can define your outer closure with a return type which helps you to set explicit lifetime boundaries for your inner closure. (By using for<> which is a Higher Ranked Trait Bound, you can find more details in here).

Inner closure needed to be Boxed because the size of Fn trait is not known at compile time.

let closure = |lower, upper| -> Box<for<'a> Fn(&BTreeSet<&'a str>) -> BTreeSet<&'a str>> {
        Box::new(move |s: &BTreeSet<&str>| {
            let mut r = BTreeSet::new();
            r.extend(s.range(lower..=upper));
            r
        })
    };

Playground

Ömer Erden
  • 7,680
  • 5
  • 36
  • 45