How to make a mutable reference from Child to Parent?

Hello everyone
How to make a mutable reference from Child to Parent?

Smth like a Rust Playground

use std::cell::RefCell;

struct Child {
    parent: RefCell<Parent>,
}

impl Child {
    pub fn new (parent: RefCell<Parent>) -> Self {
        Self {
            parent: parent,
        }
    }
    pub fn print(& mut self) {
        println!("{}", self.parent.borrow_mut().value);
    }
}

struct Parent {
    pub value: i32,
}

impl Parent {
    pub fn new() -> Self {
        Self {
            value: 0,
        }
    }
    pub fn create_child(&self) -> Child {
        Child::new(RefCell::new(self))
    }
}

fn main() {
    let mut p = Parent::new();
    let mut c = p.create_child();
    c.print();
}

but this snipped is failing with

29  |         Child::new(RefCell::new(self))
    |                    ------------ ^^^^ expected `Parent`, found `&Parent`
    |                    |
    |                    arguments to this function are incorrect

Parent can create instance of Childs, but Parent also has some shared mutable field, that accessible for all childs.

Any ideas?

How about something like this?

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

pub struct Child {
    parent: Parent,
}

impl Child {
    pub fn new(parent: Parent) -> Self {
        Self { parent: parent }
    }

    pub fn print(&mut self) {
        println!("{}", self.parent.0.borrow_mut().value);
    }
}

#[derive(Clone)]
pub struct Parent(Rc<RefCell<ParentInner>>);

struct ParentInner {
    value: i32,
}

impl Parent {
    pub fn new() -> Self {
        Self(Rc::new(RefCell::new(ParentInner { value: 0 })))
    }

    pub fn value(&self) -> i32 {
        self.0.borrow().value
    }

    pub fn create_child(&self) -> Child {
        Child::new(self.clone())
    }
}

fn main() {
    let p = Parent::new();
    let mut c = p.create_child();
    c.print();
}

Playground.

3 Likes

Any time you need multiple mutable handles to the same data in Rust, you'll need an Rc<RefCell<T>> or something like it. (Playground example)

Arc<Mutex<T>> is the same thing but thread-friendly.

But avoid shared mutable state when you can. Some other way might be nicer—it really depends on what you're trying to do. For example, if the Parent has a Vec<Child> of children, and all you're trying to do is maintain some statistics in the Parent that are updated by some Child methods, then consider having the Parent pass &mut self.stats in to each child method that needs it. In that case you don't need any Arc/Rc/RefCell/Mutex anywhere, plus you save a little memory per Child.

2 Likes

bah, @jofas beat me to it, great minds think alike

2 Likes

Thank you, very helpful!

To maintain both mutation and traversal capabilities for a graph, one effective approach is to delegate node ownership to a distinct collection.

For example, you can store nodes in a Vec<Node> and use integer indices within the Node struct to reference children and parents:

let my_graph = Vec::<Node>::new();

struct Node {
    parent: usize, // Index into `my_graph`
    children: Vec<usize>, // Indices into `my_graph`
}

You might also consider crates like Slab or SlotMap, which provide more concise and reusable ways to manage vector indices.

This approach has drawbacks, such as non-contiguous memory usage and the need to always access the node collection. However, it's highly flexible and, in many cases, performs at least as well as the self-owning Rc<RefCell<Node>> approach.

1 Like