I cannot find a way to do simple tree traversal without recursion within the guidelines of the borrow checker.
Advent of Code 2021 Day 18 has numbers that can be represented either by a pair of numbers or by a value (perfect for Rust enums). There are also parts of the problem where I'm using a stack to traverse the tree so I'm using Rc<RefCell<T>>
to represent child nodes. This led me to the following representation:
use std::{cell::RefCell, rc::Rc};
enum Number {
Pair(Rc<RefCell<Number>>, Rc<RefCell<Number>>),
Value(u8),
}
I'm trying to make a function that updates the value of the left-most value in a Number
. Writing the recursive version took a few tries but ended up working. However, I cannot get an iterative version to compile no matter what I try. The combination of matching the node and having to borrow with RefMut
leads me to borrow/lifetime problems. This is what I'm trying to do:
fn propagate_left(mut node: &Rc<RefCell<Number>>, val: u8) {
loop {
let mut ref_mut = node.borrow_mut();
match &mut (*ref_mut) {
Number::Pair(left_node, _) => {
node = left_node;
}
Number::Value(number_val) => {
*number_val += val;
return;
}
}
}
}
error[E0597]: `ref_mut` does not live long enough
--> src/lib.rs:11:22
|
8 | fn propagate_left(mut node: &Rc<RefCell<Number>>, val: u8) {
| - let's call the lifetime of this reference `'1`
...
11 | match &mut (*ref_mut) {
| ^^^^^^^ borrowed value does not live long enough
12 | Number::Pair(left_node, _) => {
| --------- assignment requires that `ref_mut` is borrowed for `'1`
...
20 | }
| - `ref_mut` dropped here while still borrowed
Is there any way to make this work without using unsafe code or recursion?
I used a Vec
for storage and indices in my structures to avoid this kind of problem in other puzzles but I wanted to try with references in this one.