The goal here is to implement a basic binary tree with values only on leaves, with depth
, mirror
, and in_order
(traversal) operations.
I have not used Rust before.
Some particular questions I have:
- In a few places, I'm defining methods by passing
self
by reference and then matching on its derefenced form. I then have to borrow the fields withref
in the destructuring. Is this the intended form? - Is
into_in_order
usingVec
properly/optimally? (I tried to use justlv.extend(&mut rv)
but got an error that that particular method was still under churn and I should wait for "the dust to settle.") - Am I using
Box
es correctly? When should I useBox
es vs.* const
s? - Why do
(*r).mirror()
andr.mirror()
do the same thing? I would have expected the latter to throw becauseBox
es don't have amirror
method. - Is there a less verbose alternative to the
Branch(Box::new(Branch(…)))
syntax?
#[derive(Debug, PartialEq, Clone)] enum BTree<T> { Leaf(T), Branch(Box<BTree<T>>, Box<BTree<T>>), } impl <T> BTree<T> { fn depth(&self) -> i32 { match *self { BTree::Leaf(_) => 1, BTree::Branch(ref l, ref r) => std::cmp::max(l.depth(), r.depth()) + 1, } } fn into_in_order(self) -> Vec<T> { match self { BTree::Leaf(val) => vec!(val), BTree::Branch(l, r) => { let mut lv = l.into_in_order(); let rv = r.into_in_order(); lv.extend(rv.into_iter()); lv } } } } impl <T : Clone> BTree<T> { fn mirror(&self) -> BTree<T> { match *self { BTree::Leaf(_) => (*self).clone(), BTree::Branch(ref l, ref r) => BTree::Branch(Box::new((*r).mirror()), Box::new((*l).mirror())), // // why does this work? // BTree::Branch(Box::new(r.mirror()), Box::new(l.mirror())), } } } #[test] #[allow(unused_variables)] fn test_btree_creation() { use BTree::*; let leaf: BTree<i32> = Leaf(10); let branch: BTree<i32> = Branch(Box::new(Leaf(15)), Box::new(Leaf(20))); let tree: BTree<i32> = Branch(Box::new(branch.clone()), Box::new(Leaf(30))); assert_eq!(branch, branch.clone()); } #[test] fn test_btree_depth() { use BTree::*; assert_eq!(Leaf(10).depth(), 1); let branch: BTree<i32> = Branch(Box::new(Leaf(15)), Box::new(Leaf(20))); assert_eq!(branch.depth(), 2); let tree: BTree<i32> = Branch(Box::new(branch.clone()), Box::new(Leaf(30))); assert_eq!(tree.depth(), 3); let other_tree: BTree<i32> = Branch( Box::new(branch.clone()), Box::new(branch.clone())); assert_eq!(other_tree.depth(), 3); } #[test] fn test_btree_mirror() { use BTree::*; assert_eq!(Leaf(10).mirror(), Leaf(10)); assert_eq!( Branch(Box::new(Leaf(10)), Box::new(Leaf(20))).mirror(), Branch(Box::new(Leaf(20)), Box::new(Leaf(10)))); assert_eq!( Branch( Box::new(Leaf(10)), Box::new(Branch(Box::new(Leaf(20)), Box::new(Leaf(30)))) ).mirror(), Branch( Box::new(Branch(Box::new(Leaf(30)), Box::new(Leaf(20)))), Box::new(Leaf(10)))); } #[test] fn test_btree_in_order() { use BTree::*; assert_eq!(Leaf(10).into_in_order(), vec!(10)); assert_eq!(Branch(Box::new(Leaf(10)), Box::new(Leaf(20))).into_in_order(), vec!(10, 20)); assert_eq!( Branch( Box::new(Leaf(10)), Box::new(Branch(Box::new(Leaf(20)), Box::new(Leaf(30)))) ).into_in_order(), vec!(10, 20, 30)); }
I also have the following macro definitions (not all used above):
macro_rules! assert_eq { ($actual:expr, $expected:expr) => ( if $expected != $actual { panic!("expected {:?}, but got {:?}", $expected, $actual); } ) } macro_rules! assert_neq { ($actual: expr, $expected_not: expr) => ( if $expected_not == $actual { panic!("expected {:?} not to equal {:?}", $expected_not, $actual); } ) } macro_rules! assert_approx { ($actual: expr, $expected: expr) => { if ($expected - $actual).abs() > 1e-3 { panic!("expected {:?} or similar, but got {:?}", $expected, $actual); } } }