Reputation: 109
I am writing a tree in Rust and I want to implement a function:left
which can turn a tree's root into the tree's root's left child.
Here is my code:
struct Node {
value: i32,
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
struct Tree {
root: Option<Box<Node>>,
}
enum Error {
DuplicateValue,
NotFound,
EmptyTree
}
impl Tree {
fn left(&mut self) -> Result<(), Error> {
match self.root {
Option::None => return Err(Error::EmptyTree),
Option::Some(ref mut node) => {
*node = node.left.as_ref().unwrap();
return Ok(())
}
}
}
}
and the error says
mismatched types
expected struct `Box<Node>`
found reference `&Box<Node>`
I have tried many methods and look up a lot of information but I still cannot fix this. I think it is a very simple thing in C, just like:
*root = *(root->left);
but why is it so hard in Rust? Can anyone help me?
Upvotes: 4
Views: 1634
Reputation: 18619
You probably want to replace the entire Option
in self.root
, not just the value inside the Some()
(so that even when left
is None
, you don't panic but assign it to self.root
).
The second problem you're facing is that you have to move the left
branch out from the old root in order to be able to give its ownership to self.root
. Normally, you wouldn't be able to do that, since you only have a mutable reference. Fortunately Option::take()
is here to help: it lets you take ownership of a value in a &mut Option
, changing it to None
.
Now that you own the old tree, you can easily assign its left subtree to self.root
.
Finally, instead of the match
thing you had, you can just convert the Option
into a Result
via Option::ok_or()
and short-circuit or extract the value with ?
:
fn left(&mut self) -> Result<(), Error> {
let old_root = self.root.take().ok_or(Error::EmptyTree)?;
self.root = old_root.left;
Ok(())
}
Upvotes: 1
Reputation: 10218
Since your code looks like it throws away the whole right branch and the root node when calling left
, i.e. you aren't concerned with the original root (it will be dropped after the assignment), you can simply take
the left node out of the Option
:
impl Tree {
fn left(&mut self) -> Result<(), Error> {
match self.root {
Option::None => Err(Error::EmptyTree),
Option::Some(ref mut node) => {
*node = node.left.take().unwrap();
Ok(())
}
}
}
}
Note however that this will panic if the left subtree is empty. If you want to make self
empty in this case, you want to replace the whole Option
, not the value inside it. In this case, you have to first do the matching, return early in the empty case, and only then, after the root
is no longer borrowed, do the replacement:
impl Tree {
fn left(&mut self) -> Result<(), Error> {
let node = match self.root {
Option::None => return Err(Error::EmptyTree),
Option::Some(ref mut node) => node.left.take(),
};
self.root = node;
Ok(())
}
}
Upvotes: 5
Reputation: 1215
Use clone()
with #[derive(Clone)]
#[derive(Clone)]
struct Node {
value: i32,
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
struct Tree {
root: Option<Box<Node>>,
}
enum Error {
DuplicateValue,
NotFound,
EmptyTree
}
impl Tree {
fn left(&mut self) -> Result<(), Error> {
match self.root {
Option::None => return Err(Error::EmptyTree),
Option::Some(ref mut node) => {
*node = node.left.clone().unwrap();
return Ok(())
}
}
}
}
Upvotes: -1