35

I'd like to have struct members that know their parent. This is approximately what I'm trying to do:

struct Parent<'me> {
    children: Vec<Child<'me>>,
}

struct Child<'me> {
    parent: &'me Parent<'me>,
    i: i32,
}

fn main() {
    let mut p = Parent { children: vec![] };
    let c1 = Child { parent: &p, i: 1 };
    p.children.push(c1);
}

I tried to appease the compiler with lifetimes without completely understanding what I was doing.

Here's the error message I'm stuck on:

error[E0502]: cannot borrow `p.children` as mutable because `p` is also borrowed as immutable
  --> src/main.rs:13:5
   |
12 |     let c1 = Child { parent: &p, i: 1 };
   |                               - immutable borrow occurs here
13 |     p.children.push(c1);
   |     ^^^^^^^^^^ mutable borrow occurs here
14 | }
   | - immutable borrow ends here

That makes some sense, but I'm not at all sure where to go from here.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Grumdrig
  • 16,588
  • 14
  • 58
  • 69

1 Answers1

30

It is not possible to create cyclic structures with borrowed pointers.

There is not any good way of achieving cyclic data structures at present; the only real solutions are:

  1. Use reference counting with Rc<T> with a cyclic structure with Rc::new and Rc:downgrade. Read the rc module documentation and be careful to not create cyclic structures that use strong references, as these will cause memory leaks.
  2. Use raw/unsafe pointers (*T).
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
  • Thanks; very good to know. I guess I'll see if I can refactor the smarts in the Child up to the Parent and get rid of the need for the parent pointer. – Grumdrig Dec 20 '13 at 16:07
  • Actually, that idea is a small nightmare, and `*T` seems like exactly what I want. But I can't seem to use it to access the members of Parent. When I try to use `c1.parent.i` (assuming Parent has a `i:int` field, not shown in my example), I get `error: attempted access of field 'i' on type '*Parent', but no field with that name was found`. I can't find much in the way of information about these beasts. – Grumdrig Dec 20 '13 at 17:05
  • 1
    Never mind. Rust doesn't auto-sugarize unsafe pointers, so `(*c1.parent).i` works (in an `unsafe` block). – Grumdrig Dec 20 '13 at 17:16
  • 3
    If the child object stores `std::rc::Weak` instead of `Rc`, it should work fine without `new_unchecked`, as there will be no (strong) cyclic references. – Pavel Strakhov Sep 04 '16 at 22:13
  • Is this answer still valid? – Ekrem Dinçel Dec 31 '20 at 07:51
  • 1
    @EkremDinçel: yes, and it’s extremely unlikely to ever change. – Chris Morgan Jan 03 '21 at 19:29