Parent-child relation with Rc/RefCell not working - rust

I just started with rust and am trying to implement a struct that has a parent and child.
The function set_child updates the child of the current X and sets the child's parent to be the current X, but I'm encountering many problems that I have a very rough understanding of and can't fix.
Any help is appreciated :)
main.rs
use std::{rc::Rc, cell::RefCell, borrow::BorrowMut};
struct X {
parent: Option<Rc<RefCell<X>>>,
child: Option<Rc<RefCell<X>>>,
value: i32,
}
impl X {
fn new() -> Self {
X {
parent: None,
child: None,
value: 10
}
}
fn set_child(&self, obj: Rc<RefCell<X>>) {
self.borrow_mut().child = Some(obj);
let &mut child = match self.child {
Some(x) => x.borrow_mut(),
None => todo!()
};
// no field `parent` on type `Rc<RefCell<X>>`
// and there is an error that says I cannot pass `self`
// it has to be a `Rc<RefCell<X>>`
child.parent = self;
}
}

Related

Cannot borrow as mutable, getting a mutable reference from a borrowed value [duplicate]

This question already has answers here:
How to handle "temporary value dropped" error when adapting Box-based tree structure to Rc+RefCell?
(2 answers)
Closed last month.
I was following this other post: Understanding Rust `Rc<RefCell<_>>` where op tried implementing a tree with Box and was successful in doing it but then tried implementing it with Rc and RefCell and found issues. The accepted answer compiles but doesn't work because it doesn't add nodes to the root. I tried updating the accepted answer a bit to try and get it to work but wasn't able to. Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference. But then if a borrow_mut() I get that value is a private field, so I'm assuming I can't access any properties of the contained value if it is a mutable reference?
What should I do to get this code to work?
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt;
#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
root: Option<Box<NodeBox<T>>>,
}
#[derive(Debug, Clone)]
struct NodeBox<T> {
value: T,
left: Option<Box<NodeBox<T>>>,
right: Option<Box<NodeBox<T>>>,
}
impl<T: Ord> TreeBox<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Option::Some(current_node) = node {
match current_node.value.cmp(&value) {
Ordering::Less => node = &mut current_node.right,
Ordering::Equal => return false,
Ordering::Greater => node = &mut current_node.left,
}
}
*node = Option::Some(Box::new(NodeBox {
value,
left: Option::None,
right: Option::None,
}));
return true;
}
}
#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
root: Option<Rc<RefCell<Node<T>>>>,
}
#[derive(Debug, Clone, PartialEq)]
struct Node<T> {
value: T,
left: Option<Rc<RefCell<Node<T>>>>,
right: Option<Rc<RefCell<Node<T>>>>,
}
impl<T: Ord + fmt::Debug> Tree<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
let mut node = &mut self.root;
while let Some(current_node) = node {
let current_node = current_node.borrow();
let cmp = current_node.value.cmp(&value);
let new_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
node = new_node;
}
// let mut node = &mut node;
*node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
true
}
}
fn main() {
let mut tree_box = TreeBox::new();
tree_box.insert(1);
tree_box.insert(2);
tree_box.insert(3);
let mut tree = Tree::new();
tree.insert(1);
tree.insert(2);
tree.insert(3);
println!("TreeBox: {:?}", tree_box);
println!("Tree: {:?}", tree);
}
The accepted answer compiles but doesn't work because it doesn't add nodes to the root.
You are right, and fixing the original solution, here a version that add the root node correctly:
pub fn insert(&mut self, value: T) -> bool {
//if no root, just create one
let mut node = if let Some(root) = &self.root {
Rc::clone(root)
} else {
self.root = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
return true;
};
loop {
let current_node = Rc::clone(&node);
let mut current_node = RefCell::borrow_mut(&current_node);
let cmp = current_node.value.cmp(&value);
let next_node = match cmp {
Ordering::Less => &mut current_node.left,
Ordering::Equal => return false,
Ordering::Greater => &mut current_node.right,
};
if let Some(next_node) = next_node {
node = Rc::clone(next_node);
} else {
*next_node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
return true;
}
}
}
Basically I'm trying to get mutable references in the loop and I can't because I borroed an immutable reference.
The problem is slightly different. what happens is that you can't walk this Rc<RefCell> tree, at least not interactively like this, because the "borrow" of such structures need to be keep while you are working with it. And your implementation releases the "borrow" after each loop.
But then if a borrow_mut() I get that value is a private field, so I'm
assuming I can't access any properties of the contained value if it is
a mutable reference?
Not really, what is happening here is that you are not calling the function RefCell::borrow_mut that returns a RefMut<Node>, you are in fact calling <Rc as BorrowMut>::borrow_mut that returns &mut RefMut<...>. And by accessing the value you are trying the access the private field value from RefCell, not Node.
Notice that in my implementation I explicitly called RefCell::borrow_mut, that fixes this issue.

Keeping track of a (child) struct who called a method in Rust

I would like to create a add_ten method for MyStruct which keeps track of the child that called it (as a reference).
struct MyStruct<'a> {
value: i32,
child: Option<&'a mut MyStruct<'a>>,
}
impl MyStruct<'_> {
fn add_ten(&mut self) -> MyStruct {
MyStruct {
value: self.value + 10,
child: Some(self),
}
}
}
fn main() {
let mut a = MyStruct { value: 10, child: None }; // Create some struct
let b = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("{}", a.value); // Be able to read the value here
println!("{}", b.value); // and here
}
However I get this error:
error: lifetime may not live long enough
--> src/main.rs:10:9
|
9 | fn add_ten(&mut self) -> MyStruct {
| ---------
| |
| let's call the lifetime of this reference `'1`
| has type `&mut MyStruct<'2>`
10 | / MyStruct {
11 | | value: self.value + 10,
12 | | child: Some(self),
13 | | }
| |_________^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
= note: requirement occurs because of the type `MyStruct<'_>`, which makes the generic argument `'_` invariant
= note: the struct `MyStruct<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
I understand that its a lifetime error, but I'm kind of stuck here :) I hope what I'm asking is clear enough, any help is appreciated!
EDIT
The reason I would like to use a reference, is to be able to come back to the childs and modify them. Something looking like this:
struct MyStruct<'a> {
value: i32,
child: Option<&'a mut MyStruct<'a>>,
}
impl MyStruct<'_> {
fn add_ten(&mut self) -> MyStruct {
MyStruct {
value: self.value + 10,
child: Some(self),
}
}
fn set_childs_to_zero(self) {
if self.child.is_none() { return; }
let mut child = self.child.unwrap();
loop {
child.value = 0;
if child.child.is_none() { break; }
child = child.child.unwrap();
}
}
}
fn main() {
let mut a = MyStruct { value: 10, child: None }; // Create some struct
let b = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("a: {}", a.value); // 10
println!("b: {}", b.value); // 20
b.set_childs_to_zero();
println!("a: {}", a.value); // 0
}
This might be a weird way of achieving what you are looking for. I doubt that it is the "right" way but hopefully someone can build off this and provide a better solution.
use std::rc::Rc;
struct MyStruct {
value: i32,
child: Option<Rc<MyStruct>>,
}
impl MyStruct {
fn add_ten(self) -> (Rc<MyStruct>, MyStruct) {
let s = Rc::new( self );
(
s.clone(),
MyStruct {
value: s.value + 10,
child: Some(s),
}
)
}
}
fn main() {
let a = MyStruct { value: 10, child: None }; // Create some struct
let (a, b) = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("{}", a.value); // Be able to read the value here
println!("{}", b.value); // and here
}
The use case you are describing is what Rc was built for - providing multiple ownership. You can read more about that in the documentation.

How to use methods of a different struct?

I have a BSTNode struct with an insert function in it:
pub struct BSTNode {
pub value: i32,
pub left: Option<Box<BSTNode>>,
pub right: Option<Box<BSTNode>>,
}
impl BSTNode {
pub fn insert(&mut self, val: i32) {
if val <= self.value {
match self.left {
None => {
self.left = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
} else {
match self.right {
None => {
self.right = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
}
}
}
I also have a BST struct to store that Node
struct BST {
node: Option<BSTNode>,
}
Is it possible to call the insert func implemented on the BSTNode through the BST struct?
What I mean is, that in the main.rs I could do this:
let mut root = BST::BST::new();
root.insert(5) // getting error obviously because method does not exist on BST struct.
Is it possible to kind of point to that BSTNode method what I call 'insert' through the BST struct?
I tried to just implement this method in the BST struct instead of keeping it in the BSTNode struct, but I am encountering a lot of problems, although that will be my last resort.
Keep it simple stupid solution: Just make an explicit delegator.
impl BST {
pub fn insert(&mut self, val: i32) {
if let Some(node) = self.node.as_mut() {
node.insert(val);
}
}
}
No need to reimplement anything, and the extra function call will almost certainly get inlined out unless you go out of your way to impede optimizations.

Parent <-> Child relation ownership problem

I'm just starting to learn Rust and I'm having some troubles understanding how ownership works in my case:
use std::ops::IndexMut;
// ================================================
struct Container {
root: Option<ContainerItem>,
items: Vec<ContainerItem>
}
impl Container {
pub fn create_item(&mut self) -> usize {
let item = create_test_item();
let idx = self.items.len();
self.items.push(item);
return idx;
}
pub fn get_item(&mut self, index: usize) -> &mut ContainerItem {
return self.items.index_mut(index);
}
pub fn new() -> Container {
let mut x = Container {
root: None,
items: Vec::new()
};
x.root = Some(create_test_item());
return x;
}
}
// ================================================
struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: usize,
has_parent: bool
}
impl ContainerItem {
pub fn add_child(&mut self, value: &mut ContainerItem) {
value.parent = self.idx;
value.has_parent = true;
self.children.push(value.idx);
}
}
// ================================================
fn create_test_item() -> ContainerItem {
ContainerItem {
idx: 1,
children: Vec::new(),
parent: 0,
has_parent: false
}
}
fn main() {
let mut container = Container::new();
let item_index = container.create_item();
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
}
I have a Container, with ContainerItems. Each ContainerItem can have children and also has a reference to its parent (both children and the parent are stored as their index in Container's items vec). This is all fine, adding items to the container works, but when I try to add a child to Container's root item (which is a ContainerItem), it throws errors:
error[E0503]: cannot use `container.root` because it was mutably borrowed
--> src/main.rs:68:12
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^^^^^^^ use of borrowed `container`
69 | root.add_child(item);
| ---- borrow later used here
error[E0505]: cannot move out of `container.root.0` because it is borrowed
--> src/main.rs:68:17
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^ move out of `container.root.0` occurs here
69 | root.add_child(item);
| ---- borrow later used here
If I change the call to add_child to use for e.g. create_test_item() as the argument, then it works fine.
I assume this might be because Container's items field has ownership over all ContainerItems? But I'm passing it by reference to add_child so I think this shouldn't matter, since I'm not changing the owner?
I think the trouble comes from the fact that in this Parent ←→ Child relation the items are sometimes referred to with references and sometimes with indices.
So, it is not always clear when the borrow should concern the container as a whole or just one item which is a part of it.
Moreover, the root item is not stored in the same place as the other items so no index can be used to refer to it.
I reorganised your code in order to always rely on indices (as far I understand your intention; maybe it is not always equivalent to what you wanted initially).
This way, as soon we have to adjust many indices, we just borrow the container as a whole.
Consequently, the add_child() method is moved from the item implementation to the container.
Note that the has_parent boolean was also a good opportunity to switch to Option.
Note also that, as long as we borrow an item with get_item() or get_item_mut(), we cannot create new items because the reallocation inside the Vec could invalidate the references; the borrow-checker will forbid that.
pub struct Container {
root: Option<usize>, // why not implicitly alway 0?
items: Vec<ContainerItem>,
}
impl Container {
pub fn create_item(&mut self) -> usize {
let idx = self.items.len();
let item = create_test_item(idx);
self.items.push(item);
idx
}
pub fn get_item(
&self,
index: usize,
) -> &ContainerItem {
&self.items[index]
}
pub fn get_item_mut(
&mut self,
index: usize,
) -> &mut ContainerItem {
&mut self.items[index]
}
pub fn new() -> Container {
let mut this = Container {
root: None,
items: Vec::new(),
};
this.root = Some(this.create_item());
this
}
pub fn add_child(
&mut self,
parent_idx: usize,
child_idx: usize,
) {
// forget child in previous parent if any
if let Some(prev_parent_idx) = self.items[child_idx].parent {
let prev_children = &mut self.items[prev_parent_idx].children;
let idx = prev_children.iter().position(|i| *i == child_idx);
prev_children.remove(idx.unwrap());
}
// give the child its new parent
let child = &mut self.items[child_idx];
child.parent = Some(parent_idx);
// append this new child to the parent
let parent = &mut self.items[parent_idx];
parent.children.push(child_idx);
}
}
#[derive(Debug)]
pub struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: Option<usize>,
}
fn create_test_item(idx: usize) -> ContainerItem {
ContainerItem {
idx,
children: Vec::new(),
parent: None,
}
}
fn main() {
let mut container = Container::new();
let item_idx = container.create_item();
println!("item: {:?}", container.get_item(item_idx));
if let Some(root_idx) = container.root {
println!("root: {:?}", container.get_item(root_idx));
println!("~~~~~~~~");
container.add_child(root_idx, item_idx);
println!("item: {:?}", container.get_item(item_idx));
println!("root: {:?}", container.get_item(root_idx));
}
}
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
container.get_item has already borrowed a value from &self. Therefore root.add_child will be restricted as long as that borrow exists.
Since the goal is simply to add an element to vec, there is no need to even have the attribute root: Option<ContainerItem>. By default when a new container is created, items can be an empty vector and when there is an item to be added it can be pushed to the vector.
Here is a simple way to implement the parent-child relationship
struct Parent<'a> {
children: &'a mut Vec<Child>,
}
impl Parent<'_> {
pub fn add(&mut self, c: Child) -> () {
let root = &mut self.children;
root.push(c)
}
pub fn get_item(
&self,
index: usize,
) -> &Child {
&self.children[index]
}
}
struct Child {
i: i32,
}
fn main() {
let c1 = Child { i: 1 };
let mut data = vec![c1];
let c12 = Child { i: 1 };
data.push(c12);
let mut p = Parent { children: &mut data };
let c12 = Child { i: 2 };
p.add(c12);
let item = p.get_item(2);
println!("{}", item.i) //2
Obviously other traits can be added to the parent

Nested struct with reference

I have some nested structs and cannot create a back reference to the parent struct. An example:
struct Foo<'a> {
parent: &'a Bar<'a>,
}
impl<'a> Foo<'a> {
fn new(parent: &'a Bar) -> Self {
Foo { parent: parent }
}
fn hello_world(&self) -> String {
self.parent.hello().to_owned() + " world"
}
}
struct Bar<'b> {
child: Option<Foo<'b>>,
data: &'static str,
}
impl<'b> Bar<'b> {
fn new() -> Self {
Bar {
child: None,
data: "hello",
}
}
fn hello(&self) -> &str {
self.data
}
fn get_foo(&self) -> Option<&Foo> {
self.child.as_ref()
}
}
fn main() {
let bar = Bar::new();
assert_eq!("hello", bar.hello());
match bar.get_foo() {
Some(foo) => assert_eq!("hello world", foo.hello_world()),
None => (),
}
}
How can I replace None with Some<Foo> with a reference to Bar? So far I'm not sure that it is possible.
It's not exactly a drop-in solution for your example, but I believe you can create "circular references" as you specify using Arc and RwLock. The API is not exactly the same (e.g., parent is an optional field), I renamed some objects, and it is definitely more verbose, but your tests pass!
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)]
struct Child {
parent: Option<Arc<RwLock<Parent>>>
}
impl Child {
fn new() -> Self {
Child {
parent: None
}
}
fn hello_world(&self) -> String {
let x = self.parent.as_ref().unwrap().clone();
let y = x.read().unwrap();
y.hello().to_owned() + " world"
}
}
#[derive(Debug, Clone)]
struct Parent {
child: Option<Arc<RwLock<Child>>>,
data: &'static str
}
impl Parent {
fn new() -> Self {
Parent {
child: None,
data: "hello"
}
}
fn hello(&self) -> &str {
self.data
}
fn get_child(&self) -> Option<Arc<RwLock<Child>>> {
self.child.as_ref().map(|x| x.clone() )
}
}
fn main() {
let parent = Arc::new(RwLock::new(Parent::new()));
let child = Arc::new(RwLock::new(Child::new()));
parent.write().unwrap().child = Some(child.clone());
child.write().unwrap().parent = Some(parent.clone());
assert_eq!("hello", parent.read().unwrap().hello());
{
let x = parent.read().unwrap();
match x.get_child() {
Some(child) => { assert_eq!("hello world", child.read().unwrap().hello_world()); }
None => {},
}
}
}
I have a similar problem, and am not entirely satisfied with the proposed solutions.
If your structure is really nested (i.e. you have a notion of "parent" and "child", with a unique parent for each child), then it seems natural that the parent should own the child(ren). So using Rc/Arc (which are designed to allow for multiple owners) does not look like the right solution -- all the less so because, as #Shepmaster points out, it "encourages" (or at least allows) the creation of cyclic references.
My idea was to have each child hold a raw pointer to its parent:
pub struct Node {
parent: *mut Node,
// ...
}
Since a node is owned by its parent, it can only be borrowed (resp. mutably borrowed) while its parent is being borrowed (resp. mutably borrowed). So in that context, it should be safe to cast self.parent to a &Node (resp. &mut Node, if self is mutable).
impl Node {
pub fn get_parent(&self) -> Option<&Node> {
unsafe { self.parent.as_ref() }
}
pub fn get_mut_parent(&mut self) -> Option<&mut Node> {
unsafe { self.parent.as_mut() }
}
}
However, this requires that the address of the parent node never changes (i.e. the parent is never moved). This can be achieved by only ever handling boxed nodes.
pub struct Node {
parent: *mut Node,
children: Vec<Box<Node>>,
// ..
}
impl Node {
pub fn new(data: &str) -> Box<Node> {
Box::new(Node {
parent: std::ptr::null_mut(),
children: vec![],
// ..
})
}
pub fn append_child(&mut self, mut child: Box<Node>) -> usize {
child.parent = self;
self.children.push(child);
self.children.len() - 1
}
}
I implemented a full-fledged example in the playground.

Resources