Another lifetime issue


#1

This code can not compile, why?

struct Game<'a> {
	messages : Vec<&'a Message>
}

struct Message {

}

impl<'a> Game<'a> {
	fn send_message(&mut self, msg : &Message) {
		self.messages.push(msg);
	}
}

The error is:

error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src\main.rs:19:28
   |
19 |         self.messages.push(msg);
   |                            ^^^
   |
note: ...the reference is valid for the lifetime 'a as defined on the body at 18:47...
  --> src\main.rs:18:48
   |
18 |       fn send_message(&mut self, msg : &Message) {
   |  ________________________________________________^ starting here...
19 | |         self.messages.push(msg);
20 | |     }
   | |_____^ ...ending here
note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the body at 18:47
  --> src\main.rs:18:48
   |
18 |       fn send_message(&mut self, msg : &Message) {
   |  ________________________________________________^ starting here...
19 | |         self.messages.push(msg);
20 | |     }
   | |_____^ ...ending here

#2

Because msg arg provided to send_message() may not outlive Game. You just need to tell rustc that will not happen by specifying the lifetime for msg:

impl<'a> Game<'a> {
	fn send_message(&mut self, msg : &'a Message) {
		self.messages.push(msg);
	}
}

#3

Without explicitly annotating lifetimes the compiler assumes you meant this:

impl<'a> Game<'a> {
	fn send_message<'borrow>(&'borrow mut self, msg : &'borrow Message) {
		self.messages.push(msg);
	}
}

'borrow is only guaranteed to be valid until the end of Game's send_message method. But you need to promise the compiler it will be valid at least as long as 'a. This is what the compiler was trying to report. So, knowing that, this should compile:

impl<'a> Game<'a> {
	fn send_message(&mut self, msg : &'a Message) {
		self.messages.push(msg);
	}
    
}

Note that the 'borrow lifetime is elided like it was in your original, but as before it is still there implicitly.

(Hopefully I didn’t butcher the wording too bad).


edit: Actually, after revisiting the elision rules documentation, the compiler probably assumed it was this (but it’s still invalid because 'c still isn’t valid for all 'a):

impl<'a> Game<'a> {
	fn send_message<'b, 'c>(&'b mut self, msg : &'c Message) {
		self.messages.push(msg);
	}
}

#4

You have to think about why you are supplying a lifetime in the first place. You’ve created a lifetime, named 'a, and you have assigned 'a to each Message reference in the messages field. So then, who is 'a referring to? It’s a parameter that’s supplied as an input to a method of your struct. You need to designate that parameter with the 'a lifetime to make the compiler aware that your msg parameter is where the 'a values are coming from.


#5
impl<'a> Game<'a> {
	fn send_message<'b, 'c>(&'b mut self, msg : &'c Message) {
		self.messages.push(msg);
	}
}

since arg self is Game itself, why 'b is not 'a?


#6

'reference ’ means what?
‘borrowed content’ means what?


#7

That actually means:

fn send_message<'b, 'c>(self: &'b mut Game<'a>, msg : &'c Message)

'a in the referrent provides an upper bound on the life time 'b. It is however possible to have a reference to a Game<'a> where the reference itself has a shorter life time.