syakhmi
syakhmi

Reputation: 41

How do I return a reference to a closure's argument from the closure?

I am a Rust newbie, and don't understand all the rules for lifetime elision and inference. I can't seem to get returning a reference into an argument from a closure to work, and the errors don't help much for someone with my amount of knowledge.

I can use a proper function with lifetime annotations in place of a closure, but can't figure out a way to annotate these lifetimes on the closure.

struct Person<'a> {
    name: &'a str,
}

impl<'a> Person<'a> {
    fn map<F, T>(&'a self, closure: F) -> T
        where F: Fn(&'a Person) -> T
    {
        closure(self)
    }
}

fn get_name<'a>(person: &'a Person) -> &'a str {
    person.name
}

fn main() {
    let p = Person { name: "hello" };
    let s: &str = p.map(|person| person.name); // Does not work
    // let s: &str = p.map(get_name);  // Works
    println!("{:?}", s);
}

And here is the compiler error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:19:34
   |
19 |     let s: &str = p.map(|person| person.name); // Does not work
   |                                  ^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 19:33...
  --> src/main.rs:19:34
   |
19 |     let s: &str = p.map(|person| person.name); // Does not work
   |                                  ^^^^^^^^^^^
note: ...so that expression is assignable (expected &str, found &str)
  --> src/main.rs:19:34
   |
19 |     let s: &str = p.map(|person| person.name); // Does not work
   |                                  ^^^^^^^^^^^
note: but, the lifetime must be valid for the method call at 19:18...
  --> src/main.rs:19:19
   |
19 |     let s: &str = p.map(|person| person.name); // Does not work
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that pointer is not dereferenced outside its lifetime
  --> src/main.rs:19:19
   |
19 |     let s: &str = p.map(|person| person.name); // Does not work
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^

What is happening here, and how to change the closure for it to work?

Upvotes: 3

Views: 494

Answers (1)

syakhmi
syakhmi

Reputation: 41

I think I was confusing the lifetime of reference to the Person with the lifetime parameter of the struct (of the &str reference). This compiles:

struct Person<'a> {
    name: &'a str,
}

impl<'a> Person<'a> {
    fn map<F, T>(&self, closure: F) -> T
        where F: Fn(&Person<'a>) -> T
    {
        closure(self)
    }
}

fn get_name<'a>(person: &Person<'a>) -> &'a str {
    person.name
}

fn main() {
    let p = Person { name: "hello" };
    println!("{:?}", p.map(|person| person.name));
    println!("{:?}", p.map(get_name));
}

I'm not sure if my understanding of the lifetime annotations is correct, and perhaps someone else can pick apart the compiler error above. The language is extremely confusing.

Upvotes: 1

Related Questions