Lifetime issue. Again


#1

Here’s my code:

struct A<'a>(&'a mut u8);

impl<'a> A<'a> {
    fn g(&'a mut self) -> &'a mut u8
    {
        self.0
    }
}

fn call_closure<F>(f: F)
where
    F: FnOnce(&mut A),
{
    let mut x = 5;
    let mut a = A(&mut x);
    f(&mut a)
}

fn main() {
    call_closure(|a| {
        a.g();
    });
}

Here’s the error message that is produced:

$ rustc trash.rs -o trashout
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> trash.rs:21:11
   |
21 |         a.g();
   |           ^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 20:18...
  --> trash.rs:20:18
   |
20 |       call_closure(|a| {
   |  __________________^
21 | |         a.g();
22 | |     });
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> trash.rs:21:9
   |
21 |         a.g();
   |         ^
note: but, the lifetime must be valid for the anonymous lifetime #3 defined on the body at 20:18...
  --> trash.rs:20:18
   |
20 |       call_closure(|a| {
   |  __________________^
21 | |         a.g();
22 | |     });
   | |_____^
   = note: ...so that the types are compatible:
           expected &mut A<'_>
              found &mut A<'_>

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.

I find this pretty opaque. What the heck is autoref? Lifetimes #2 and #3 appear to be identical. The “expected” and “found” types appear to be identical.

I think the message is trying to say it can’t infer a lifetime for the reference returned from g. I understand why that lifetime can’t outlive “borrowed content.” But what’s requiring it to live long enough? I tried a few variations on g, like this:

impl<'a> A<'a> {
    fn g<'b>(&'a mut self) -> &'b mut u8
    where
        'a: 'b
    {
        self.0
    }
}

with the same result.


#2

It should be:

fn g(&mut self) -> &mut u8
    {
        self.0
    }

That is, do not use 'a - that’s a lifetime parameter of A itself, and will require a borrow of the value for its entire lifetime. In the closure, you have a borrow of A of some lifetime (i.e. the a param) - you cannot then reborrow it for 'a, which would be reborrowing it for a longer lifetime.


#3

Awesome, thanks.

I could have sworn my first attempt looked exactly like that, and that I only added those lifetimes when that didn’t work… but no, it seems this works fine.


#4

If you find yourself writing methods that take a borrow of self for a lifetime parameter of the type itself, you can be 99.99% certain you’re doing it wrong :slight_smile:.