0

In this simplified code, I have two important structs: Owner takes ownership of an object, adds it to a Vec, and returns a reference to it; RefKeeper just holds references to objects in a Vec. Owner also has a RefKeeper.

struct Foo(i32);

struct Owner<'o> {
    list: Vec<Foo>,
    refkeeper: RefKeeper<'o>,
}

impl<'o> Owner<'o> {
    pub fn new() -> Self {
        Self {
            list: Vec::new(),
            refkeeper: RefKeeper::new(),
        }
    }

    pub fn add(&mut self, me: Foo) -> &Foo {
        self.list.push(me);
        return self.list.last().unwrap();
    }

    pub fn add_ref(&mut self, me: &'o Foo) {
        self.refkeeper.add(me);
    }
}

struct RefKeeper<'ro> {
    list: Vec<&'ro Foo>,
}

impl<'ro> RefKeeper<'ro> {
    pub fn new() -> Self {
        Self { list: Vec::new() }
    }

    pub fn add(&mut self, me: &'ro Foo) {
        self.list.push(me);
    }
}

fn main() {
    let mut owner = Owner::new();
    let a1 = Foo(1);
    let a1_ref = owner.add(a1);

    // this variant doesn't work
    owner.add_ref(a1_ref);

    // let mut refkeeper = RefKeeper::new();
    // refkeeper.add(a1_ref);

    // let a2 = Foo(2);
    // owner.add_ref(&a2);
}

Two variants work: if I make RefKeeper externally, I can store the ref returned by Owner::add; on the other hand, if I make a new object (a2), I can store &a2 in owner.refkeeper with no problem. Why does the other variant give me this error?

error[E0499]: cannot borrow `owner` as mutable more than once at a time
  --> src/main.rs:46:5
   |
43 |     let a1_ref = owner.add(a1);
   |                  ----- first mutable borrow occurs here
...
46 |     owner.add_ref(a1_ref);
   |     ^^^^^         ------ first borrow later used here
   |     |
   |     second mutable borrow occurs here

Is there something fundamentally wrong with this pattern? I'm under the impression that there should be no issue with lifetimes because all the borrows are being used in the same object.

  • What is the actual goal of `RefKeeper`? The API you've defined will have loads of problems as-is. Keep in mind that as long as a reference to a value in `list` exists, you can never insert another entry into that list, so by adding an item and then adding it to refkeeper, you'd be making it impossible to add any more items. – loganfsmyth Jun 06 '20 at 03:52

1 Answers1

0

Its because Owner::add returns a reference that is bound to the lifetime of &mut self. So as long as the return value exists (a1_ref) then the &mut self reference does too. So calling add_ref fails because it requires another mut self reference of that same instance.

You can either have one mutable reference, or many immutable references.

The reason calling refkeeper.add and then owner.add_ref is not giving you the same issue is because adding to refkeeper does not require another reference to owner.

You might want to look at std::rc::Rc.

pigeonhands
  • 3,066
  • 15
  • 26