Borrowed value does not live long enough (local vars in fn/constructor)


#1

Trying to implement some local set of exchanges with queues, each with messages.

To that end, 3 struct’s are defined, each containing references to some values, and providing a simple constructor (amongst others). When instantiating any struct, some local variables are defined within the constructor to hold the values that will be passed to the constructor of the struct.

This is the minimal example that triggers the error:

extern crate chrono;
extern crate msg_test_crate;

use chrono::{DateTime, Local};

use std::collections::VecDeque;


pub struct Exchange<'a, T: 'a> {
    pub name: String,
    pub queues: &'a mut VecDeque<Queue<'a, T>>,
    pub messages: &'a mut VecDeque<Message<T>>,
}

impl<'a, T: 'a> Exchange<'a, T> {
    pub fn new(name: String) -> Exchange<'a, T> {
        let queues: VecDeque<Queue<'a, T>> = VecDeque::new();
        let messages: VecDeque<Message<T>> = VecDeque::new();
        Exchange{name: name, messages: &mut messages, queues: &mut queues}
    }
}

pub struct Queue<'a, T: 'a> {
    pub messages: &'a mut VecDeque<Message<T>>,
}

impl<'a, T: 'a> Queue<'a, T> {
    pub fn new() -> Self {
        let messages : VecDeque<Message<T>> = VecDeque::new();
        Queue{messages: &mut messages}
    }
}

#[derive(Clone)]
pub struct Message<T>  {
    pub date: DateTime<Local>,
    pub content: T,
}

impl<T> Message<T> {
    pub fn new(content: T) -> Self {
        let now: DateTime<Local> = Local::now();
        Message{date: now, content: content}
    }
}

fn main() {
    let mut messages: VecDeque<Message<String>> = VecDeque::new();
    let queue: Queue<Message<String>> = Queue::new();
    let mut queues: VecDeque<Queue<Message<String>>> = VecDeque::new();
    messages.push_front(Message::new("Something".to_string()));
    queues.push_front(queue);
    let exc : Exchange<Message<String>> = Exchange::new("Exchange".to_string());
}

And the error itself:

error[E0597]: `messages` does not live long enough
  --> src/main.rs:21:49
   |
21 |             Exchange{name: name, messages: &mut messages, queues: &mut queues}
   |                                                 ^^^^^^^^ borrowed value does not live long enough
22 |         }
   |         - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:5...
  --> src/main.rs:17:5
   |
17 |     impl<'a, T: 'a> Exchange<'a, T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0597]: `queues` does not live long enough
  --> src/main.rs:21:72
   |
21 |             Exchange{name: name, messages: &mut messages, queues: &mut queues}
   |                                                                        ^^^^^^ borrowed value does not live long enough
22 |         }
   |         - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:5...
  --> src/main.rs:17:5
   |
17 |     impl<'a, T: 'a> Exchange<'a, T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0597]: `messages` does not live long enough
  --> src/main.rs:32:34
   |
32 |             Queue{messages: &mut messages}
   |                                  ^^^^^^^^ borrowed value does not live long enough
33 |         }
   |         - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 29:5...
  --> src/main.rs:29:5
   |
29 |     impl<'a, T: 'a> Queue<'a, T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It complains on the variables in use not able to outlive the process of construction.
What I tried so far is to avoid local variables and place directly the value, but then it’s even worse as the local variable has a shorter lifetime. Also tried different lifetimes ('a, 'b) for the queues contained in Exchange; but that triggered E0491.

Is it possible to explain, in really simple terms, why the above code is not compiling and how is it the proper way to solve it?


#2

The problem is, you’re constructing local values, which will go out of scope at the end of the function. If your structs keep references to them, those would be dangling, since the memory they’re pointing to has been deallocated (that’s what happens when the owner of a value goes out of scope. In this case, the local variable owns its value).

Since you’re keeping mutable references anyways, this means no one can hold a reference to those values to them anyways, so why don’t you let your structs own the values? Something like

pub struct Exchange<T> {
    pub name: String,
    pub queues: VecDeque<Queue<'a, T>>,
    pub messages: VecDeque<Message<T>>,
}

should do it. If you do it this way, the ownership gets transferred from the local variable to the struct, and the memory isn’t deallocated, and your values live on as long as the struct owns them (or you move them somewhere else).


#3

You’re trying to use references as if they were pointers, but they’re temporary read/write locks not pointers. Use owned values in structs.

There was a recent thread about the same problem: What is the better code design?