Search code examples
rustenumsbinary-tree

Extracting an attribute from a Box inside an enum


#[derive(Clone, Debug)]
pub struct Node<T> {
    value: T,
    left: Addr<T>,
    right: Addr<T>,
}

#[derive(Clone, Debug)]
pub enum Addr<T> {
    Addr(Box<Node<T>>),
    None,
}

impl<T> Addr<T> {
    pub fn is_none(&self) -> bool {
        matches!(&*self, Addr::None)
    }
}
impl<T> Node<T> {
    fn node_insert(mut n: Addr<T>, val: T) {
        let nd = Box::new(Node {
            value: val,
            left: Addr::None,
            right: Addr::None,
        });

        if n.is_none() {
            n = Addr::Addr(nd);
        } else {
            node_insert(n.left, val);
        }
    }
}

I'm trying to implement a simple binary tree, and in the node_insert function I can't figure out how to access the left attribute of the Node struct when calling node_insert recursively.

Nothing I've done worked and I couldn't find any answer to help with it, probably because its somehow specific.


Solution

  • Use pattern matching:

    fn node_insert(mut n: Addr<T>, val: T) {
        match n {
            Addr::None => {
                n = Addr::Addr(Box::new(Node {
                    value: val,
                    left: Addr::None,
                    right: Addr::None,
                }))
            }
            Addr::Addr(n) => Self::node_insert(n.left, val),
        }
    }
    

    However, the compiler rightfully warns:

    warning: value assigned to `n` is never read
      --> src/lib.rs:23:13
       |
    23 |             n = Addr::Addr(Box::new(Node {
       |             ^
       |
       = help: maybe it is overwritten before being read?
       = note: `#[warn(unused_assignments)]` on by default
    

    Since you took ownership of n, you're writing to a local variable and not to the tree. Instead, you should take &mut Addr:

    fn node_insert(n: &mut Addr<T>, val: T) {
        match n {
            Addr::None => {
                *n = Addr::Addr(Box::new(Node {
                    value: val,
                    left: Addr::None,
                    right: Addr::None,
                }))
            }
            Addr::Addr(n) => Self::node_insert(&mut n.left, val),
        }
    }