I know it's a redundant question with rust but it seems I can not manage to get some generality from it. So I attempted to write a simple binary tree using some code from elsewhere (at first I used a Box of options, but it seems options of box are the way to go).
#[derive(Clone)]
pub struct BinaryTree<T>
where T:Clone
{
pub val: T,
pub left : Option<Box<BinaryTree<T>>>,
pub right : Option<Box<BinaryTree<T>>>,
}
impl<T: std::clone::Clone> BinaryTree<T>
{
pub fn new(val:T) -> Self
{
BinaryTree
{
val,
left:None,
right:None,
}
}
pub fn insertleft( mut self, node: BinaryTree<T>)-> Self
{
//let old_left = mem::take(&mut self.left);
let left_option = Some(Box::new(node ));
self.left = left_option;
self
}
pub fn insertright( mut self, node: BinaryTree<T>)-> Self
{
let right_option = Some(Box::new( node ));
self.right = right_option;
self
}
}
So here is my problem. If I create a tree like that:
let tree = BinaryTree::new(1).insertleft(BinaryTree::new(2)).insertright(BinaryTree::new(3));
There is actually no problem and I can access the left value, the right value without any problem. But if I try to fill the tree step by step
let tree = BinaryTree::new(1);
tree.insertleft(BinaryTree::new(2));
tree.insertright(BinaryTree::new(3));
then I run into errors like "use of moved value: tree.left
" whether I declare tree mutable or not. I do not really get where or how the tree is supposed to be "consumed" here. If I use & mut ref
instead of ref
in the insertleft
and insertright
functions I run into similar errors such as can not move out of which is behind a mutable reference.
I read plenty of topics about such problems but I really do not get why you can not access a public field by what is in the end, more or less a setter.
Your insertleft
and insertright
functions take self
, which tranfers ownership of the BinaryTree
to those functions. They then return it, which you currently discard.
If you want to construct the tree step by step, you can store those return values in new variables to be used for the next step of construction:
let tree = BinaryTree::new(1);
let tree1 = tree.insertleft(BinaryTree::new(2));
let tree2 = tree1.insertright(BinaryTree::new(3));
Alternatively, if you don't need to chain construction and insertions, you can take &mut
reference to self
:
impl<T: std::clone::Clone> BinaryTree<T> {
pub fn insertleft(&mut self, node: BinaryTree<T>) -> &mut Self {
let left_option = Some(Box::new(node));
self.left = left_option;
self
}
pub fn insertright(&mut self, node: BinaryTree<T>) -> &mut Self {
let right_option = Some(Box::new(node));
self.right = right_option;
self
}
}
fn main() {
let mut tree = BinaryTree::new(1);
tree.insertleft(BinaryTree::new(2));
tree.insertright(BinaryTree::new(3));
// Due to returning &mut Self, this also works:
let mut tree = BinaryTree::new(1);
tree.insertleft(BinaryTree::new(2))
.insertright(BinaryTree::new(3));
}
This reference allows insertleft
and insertright
to modify tree
in place, keeping ownership of the BinaryTree
in main
. However, you can no longer chain construction and insertion because BinaryTree::new(1).insertleft(BinaryTree::new(2)).insertright(BinaryTree::new(3))
would yield a reference which is less flexible than an owned value.
For more information, see https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html and Is there a difference between using a reference, and using an owned value in Rust?