-1

I'm studying rust and I'm stuck on a question about Rc, Weak and RefCell. The use case is to implement a fully functioning tree, where each node has one parent and a list of children. The documentation provides a good starting point:

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());

    let branch = Rc::new(Node {
        value: 5,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![Rc::clone(&leaf)]),
    });

    *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
}

But. When I try to expand upon this, there's a problem with the design. I cannot add a new node to an already consisting one. The branch node has a child, but this I think is only possible because we already know leaf is going to be the one and only child before branch is created. If this is not the case, can we somehow change branch after it already has been created inside an Rc and add leaf as a child?

Or should I leave this design and adopt a design that looks more like:

#[derive(Debug)]
struct Node {
    value: i32,
    parent: Weak<RefCell<Node>>,
    children: Vec<Rc<RefCell<Node>>>,
}
hasdrubal
  • 1,024
  • 14
  • 30

1 Answers1

1

You can add new leaves with the following code:

let new_leaf = Rc::new(Node {
    value: 4,
    parent: RefCell::new(Rc::downgrade(&branch)),
    children: RefCell::new(vec![])
});

branch.children.borrow_mut().push(new_leaf);

That being said your alternative suggested Node type seems to be what most rustaceans would go with / are more familiar with.

cafce25
  • 15,907
  • 4
  • 25
  • 31
  • Clearly I don't understand Rc well enough. So apparently you can mutate an object within Rc as long as one of its members is wrapped with RefCell? I knew it could be done with a direct Rc>, but not with Rc } >. Thanks. – hasdrubal Nov 14 '22 at 14:38
  • That's the point of `RefCell` it allowes mutation of it's content and only requires a shared reference for that as you can see in the signature `fn borrow_mut(&self) -> RefMut<'_, T>` where `RefMut<'_, T>` is essentially a mutable reference `&mut T` plus runtime reference counting. – cafce25 Nov 14 '22 at 15:03