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);
}
}
}