Cannot define lifetime of 'self' when implementing trait


#1

I am stuck in a lifetime issue and wasn’t able figure out a solution. Consider the following (simplified) code (playpen link):

trait T {
    fn do_something(&mut self);
}

struct A<'a> {
    refs: Vec<&'a str>,
    original: String,
}

impl<'a> T for A<'a> {
    fn do_something(&mut self) {
        self.refs.push(&self.original);
    }
}

fn main() {
    let mut a = A {
        refs: vec![],
        original: String::new(),
    };

    a.do_something();
}

This fails with the following error message: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements. The message suggests: consider using an explicit lifetime parameter as shown: fn do_something(&'a mut self).

I added the lifetime as suggested, but consequently, rust complains again: method not compatible with trait (...). Adding the lifetime causes the method not to be compliant with the trait anymore. The following code compiles without errors (playpen link):


struct A<'a> {
    refs: Vec<&'a str>,
    original: String,
}

impl<'a> A<'a> {
    fn do_something(&'a mut self) {
        self.refs.push(&self.original);
    }
}

fn main() {
    let mut a = A {
        refs: vec![],
        original: String::new(),
    };

    a.do_something();
}

Actually, I was kind of surprised that this code even worked because I had thought it wasn’t possible to have one struct field reference each other.
But, of course I would like to implement the trait T. I would be very grateful for some help on this issue.


#2

Hmm. It looks like using &'a mut self makes that function hang on to its borrow for the entire remaining life of the object, which means you can’t actually do anything with that mutual reference.

For instance, here’s a playground trying to call do_something a second time, “error[E0499]: cannot borrow a as mutable more than once at a time”.

Or another way it might be inspected is Drop, but that gives “error: a does not live long enough”. On beta/nightly this also clarifies “borrowed value dropped before borrower”.


#3

You seem to be saying, “I’m surprised this works, but I still want this to work even more.” :confused:

Anyway, you can make the trait work just as well as your inherent impl if you give it the lifetime: play

trait T<'a> {
    fn do_something(&'a mut self);
}

struct A<'a> {
    refs: Vec<&'a str>,
    original: String,
}

impl<'a> T<'a> for A<'a> {
    fn do_something(&'a mut self) {
        self.refs.push(&self.original);
    }
}

fn main() {
    let mut a = A {
        refs: vec![],
        original: String::new(),
    };

    a.do_something();
}

#4

This cannot work, it would be unsafe.
Imagine if you mutate original later on. The reference would be dangling.

The latter example works because the object is basically borrowed forever and thus it prevents any future mutation.

Have a look at the owning_ref crate, maybe you can use it to get what you want.


#5

Thank you very much for your answers. I didn’t try calling do_something repeatedly, which is what I want to do of course. Anyway, troplin’s explanation made it clear to me that getting this example to work is impossible.
I’ll check out the owning_ref crate, and/or eventually try to refactor my code. Thanks!