2

Consider this code, ignoring the warnings:

fn main() {}

pub struct TreeNode {
    subs: Vec<TreeNode>,
}

impl TreeNode {
    pub fn do_something(&mut self) {
        if let Some(changed_node) = self.enum_node(&|_| true) {
            // Closure in real program is much more complicated and it really mutates its parameter
            self.enum_node(&|_| false); // Again, real closure is more complicated
        };
    }

    fn enum_node<'a, F>(&'a mut self, f: &F) -> Option<&'a Self>
    where
        F: Fn(&mut Self) -> bool,
    {
        if f(self) {
            Some(self)
        } else {
            for sub in &mut self.subs {
                if let Some(n) = Self::enum_node(sub, f) {
                    return Some(n);
                }
            }
            None
        }
    }
}

The sense of the function enum_nodes is to enumerate nodes of the tree, and if the closure f returns true on some node, stop enumerating and return a reference to that node.

It gives a compiler error:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:11:13
   |
9  |         if let Some(changed_node) = self.enum_node(&|_| true) {
   |                                     ---- first mutable borrow occurs here
10 |             // Closure in real program is much more complicated and it really mutates its parameter
11 |             self.enum_node(&|_| false); // Again, real closure is more complicated
   |             ^^^^ second mutable borrow occurs here
12 |         };
   |         - first borrow ends here

I realize that

  1. This problem may be solved (I didn't actually try) by using RefCell
  2. The lifetime of the first borrow of self is prolonged because the lifetime of enum_node's self parameter and return value are the same, and I assign the return value to the changed_node.

If I rewrite lines 9-12 as:

self.enum_node(&|_| true);
self.enum_node(&|_| false);

then it compiles because the lifetime of the first borrow of self ends immediately after the first call to enum_node.

That is not my question.

After the first call to enum_node ends, the only way to mutate self is via the returned value i.e. changed_node, which it is immutable. Why does the compiler continue to count the borrow as mutable, is it logical?

How can I understand this behavior of the compiler?

mrbus2007
  • 197
  • 7

0 Answers0