Visiting nodes of tree like mutable structure

Hi,
I want to go through a tree like structure which consists of nodes which can have multiple other nodes. I would like also modify these nodes. Here is my minimal example:

pub struct Node {
    id: i32,
    node_vec: Vec<Node>,
}

impl Node {
    fn new(id: i32) -> Node {
        Node {
            id: id,
            node_vec: Vec::new(),
        }
    }

    fn get_vec(&mut self) -> &mut Vec<Node> {
        &mut self.node_vec
    }
}

fn main() {
    let mut node1 = Node::new(1);
    node1.get_vec().push(Node::new(2));

    let mut vec_ref = node1.get_vec();
    let depth = 2;
    let mut current_depth = 1;
    while current_depth < depth {
        vec_ref = vec_ref.iter_mut().last().unwrap().get_vec();
        current_depth += 1;
    }
}

When I try to go deep in structure and get mut ref as shown above I get error:

error[E0506]: cannot assign to `vec_ref` because it is borrowed
  --> src/main.rs:27:9
   |
27 |         vec_ref = vec_ref.iter_mut().last().unwrap().get_vec();
   |         ^^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |         |         |
   |         |         borrow of `vec_ref` occurs here
   |         assignment to borrowed `vec_ref` occurs here

error[E0499]: cannot borrow `*vec_ref` as mutable more than once at a time
  --> src/main.rs:27:19
   |
27 |         vec_ref = vec_ref.iter_mut().last().unwrap().get_vec();
   |                   ^^^^^^^ mutable borrow starts here in previous iteration of loop
...
30 | }
   | - mutable borrow ends here

I am new in rust programming so can anyone help me correct my code or explain how such problem should be resolved properly in rust?

This is kind of a weird case, because vec_ref.iter_mut() only borrows from vec_ref, but it would be fine if it moved vec_ref since you're going to reassign it anyway. This mechanism of "re-borrowing" references is usually a convenience, but it's not what you want here.

You can use { vec_ref }.iter_mut() to force a move into that block expression, and then your code works.

Use shadowing:

let vec_ref = vec_ref.iter_mut().last().unwrap().get_vec();

nice trick :slight_smile:

wow. it really works, thanks.
So, adding this little block invalidates reference while going out of it, and returns moved object from this reference, write?

Here's a blog post about this trick: Stuff the Identity Function Does (in Rust)

1 Like