#Issues with Borrowing in Tree Like Structures

12 messages · Page 1 of 1 (latest)

vital pine
#

Hey everyone!

I have been tasked with constructing a program that uses a glorified binary tree. It has a struct that looks like this,

    left: Option<Box<Light>>,
    right: Option<Box<Light>>,
    brightness: i32,
}

I need to implement a way to read in instructions (which is complete), which include the following,

enum Instruction {
    Set(i32),
    Left,
    Right,
    Reset,
}```

To summarise, Set will set the "brightness" of the current node. Left will go down the tree to the left, Right will go down to the right, Reset will go back to the top of the tree.

This is my current main function.

```fn main() {
    let instructions = get_instructions_from_stdin();
    let mut light = Box::new(Light { left: None, right: None, brightness: 0});
    let mut curr = &mut light;
    for instruction in &instructions{
        match instruction {
            Instruction::Set(x) => curr.brightness = *x,
            Instruction::Left => match &mut curr.left {
                Some( next) => curr =  next,
                None => {
                    let mut newLight = Box::new(Light { left: None, right: None, brightness: 0});
                    
                },
            },
            Instruction::Right => todo!(),
            Instruction::Reset => todo!(),
        }
    }
    println!("{instructions:?}");
    println!("{light:?}");
}```

This problem is really based around ownership, but I just cant seem to get this to work properly.

This is the compiler error,

   |
33 |             Instruction::Left => match &mut curr.left {
   |                                        ^^^^^^^^^^^^^^
   |                                        |
   |                                        `curr.left` was mutably borrowed here in the previous iteration of the loop
   |                                        first borrow used here, in later iteration of loop```

Im just not sure howto approach this at this stage. Looking for Advice
spiral harness
#

Usually with trees and graphs you'll be wanting to look at Rc/Weak to allow multiple things to point at one another

https://doc.rust-lang.org/std/rc/struct.Rc.html
https://doc.rust-lang.org/std/rc/struct.Weak.html

In your case it's because curr is outside the loop so it needs to extend the lifetime of &mut curr.left because of the curr = next assignment

Since being able to move out of that memory location while having a borrow would be bad

next quest
#

this is just a borrowchecker limitation

#

you can do something like ```rust
struct Node<T> {
elem: T,
next: Option<Box<Node<T>>>
}

fn append<T> (mut curr_node: Box<Node<T>>, new_node: Node<T>) {
let mut curr_node = &mut curr_node;
loop {
match curr_node.next {
Some(_) => {
curr_node = curr_node.next.as_mut().unwrap()
}
None => break
}
}
curr_node.next = Some(Box::new(new_node))
}```

vital pine
#

Wow

#

😂

#

You dont understand how angry that makes me hahahaha

#

so I cant do the match with (next) inside?

#

I have to use the functions

#

.as_mut().unwrap()

next quest
#

or ```rust
pub struct Node<T> {
elem: T,
next: Option<Box<Node<T>>>,
}

pub fn append<T>(mut curr_node: Box<Node<T>>, new_node: Node<T>) {
let mut curr_node = &mut curr_node;
loop {
match &mut **curr_node {
Node { next: Some(next), ..} => {
curr_node = next;
}
Node { next, .. } => {
*next = Some(Box::new(new_node));
break;
}
}
}
}```