rustreferenceoctree

Borrow and assign to values behind & reference


So I am trying to make my own octree in Rust, but I'm having trouble with my set function. It's supposed to be recursive, and there is a point where I am matching the child node. Except, it has two errors:

  1. It can't borrow a child as mutable, because it's behind a & reference.
  2. I don't know how to create a new child if it does exist. Since my Octree holds references to child Octrees, if I try to set the reference to a new one, it will drop the value.

I am kinda at a loss. Do I need to create a trait and then create types for the root, branches, and leaves? Or is there a way to save my code?

Code that breaks:

match self.children[index] { // Here it says I can't borrow it
            Some(ref mut child) => {
                child.set(pos, val);
            },
            None => {
                let mut new_pos = self.pos.clone();
                let new_size = self.size.clone() as i32/2 ;

                match index {
                    0 => { new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); },
                    1 => { new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); },
                    2 => { new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); },
                    3 => { new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); },
                    4 => { new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); },
                    5 => { new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); },
                    6 => { new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); },
                    7 => { new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); }
                    _ => { panic!("Index out of bounds"); }
                }

                let mut new_tree = Octree::new(new_size.clone() as u8, new_pos);
                new_tree.set(pos, val);
                *self.children[index] = Some(new_tree); // Here it says I can't write to it
            }
        }

Link to octree.rs Gist


Solution

  • References are also known as borrows; their main purpose is to get temporary, “borrowed” access to a value that is owned by something else.

    When you are defining a data structure, it should almost never contain references; instead, should use owned types. Sometimes this means writing T instead of &'a T; in this case, since the structure is recursive, it needs a pointer, but an owning one rather than a borrowing one — i.e. Box.

    Change your structure definition from

    pub struct Octree<'a, T> {
        children: [&'a Option<Octree<'a, T>>; 8],
        data: Option<T>,
        size: u8,
        pos: VecI3
    }
    

    to

    pub struct Octree<T> {
        children: [Option<Box<Octree<T>>>; 8],
        data: Option<T>,
        size: u8,
        pos: VecI3
    }
    

    Notice that the structure no longer has a lifetime parameter — just as, for example, BTreeMap (a recursive structure in the standard library) does not.

    Then to insert a child node you will need to use:

    *self.children[index] = Some(Box::new(new_tree));