Simple example with Rcs and Refcells produces confusing compiler error

Hi there.

I'm trying to get comfortable w/ Rcs and RefCells. The compiler is unhappy with me; I'm stumped by this error message:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:40:18
   |
40 |             self.add_string(s)
   |                  ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 39:28...
  --> src/main.rs:39:28
   |
39 |         ss.into_iter().map(|s| {
   |                            ^^^
note: ...so that closure can access `self`
  --> src/main.rs:40:13
   |
40 |             self.add_string(s)
   |             ^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the method body at 38:5...
  --> src/main.rs:38:5
   |
38 |     pub fn add_strings(&mut self, ss: Vec<String>) -> Vec<&[String]> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the expression is assignable
  --> src/main.rs:39:9
   |
39 | /         ss.into_iter().map(|s| {
40 | |             self.add_string(s)
41 | |         }).collect()
   | |____________________^
   = note: expected `Vec<&[String]>`
              found `Vec<&[String]>`

The minimal code snippet that generated that compiler error is below:

    use std::cell::RefCell;
    use std::rc::Rc;

    pub struct Foo {
        strings: Rc<RefCell<Vec<String>>>,
        message_log: Vec<String>
    }

    impl Foo {
        fn add_message_to_log_and_print(&mut self, message: String) -> &[String] {
            let current_log_length = self.message_log.len();        
            println!("{:?}", message);
            self.message_log.push(message);
            &self.message_log[current_log_length..]
        }
        
        pub fn add_string(&mut self, s: String) -> &[String] {
            (*self.strings).borrow_mut().push(s);
            let message = "Added a string!";
            self.add_message_to_log_and_print(message.to_string())
        }

        pub fn add_strings(&mut self, ss: Vec<String>) -> Vec<&[String]> {
            ss.into_iter().map(|s| {
                self.add_string(s)
            }).collect()
        }
    }

    fn main() {
    }

Can someone help me understand what the compiler is telling me here? Thanks in advance!

This is because your add_strings method will call add_string multiple times, while keeping the returned reference from each call around. However each call to add_string might mutate self in a way that invalidates references returned by previous calls to it, e.g. the self.message_log.push(message); can cause the vector to reallocate, which would indeed break all previous references into that vector.

Note that when you have mutable access to a RefCell, you can use its get_mut method instead of borrow_mut, which cannot panic.

3 Likes