当借用实际上是不可变的时,编译器继续将借用视为可变的

时间:2018-08-13 21:56:13

标签: rust

考虑以下代码,忽略警告:

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
        }
    }
}

函数enum_nodes的含义是枚举树的节点,如果闭包f在某个节点上返回true,请停止枚举并返回对该节点的引用。

它给出了编译器错误:

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

我意识到

  1. 可以使用RefCell
  2. 解决此问题(我实际上没有尝试过)
  3. 由于self的{​​{1}}参数和返回值的寿命相同,因此延长了enum_node的第一次借用的寿命,我将返回值分配给{ {1}}。

如果我将9-12行改写为:

self
changed_node

然后进行编译,因为self.enum_node(&|_| true); 的第一次借用的生存期在首次调用self.enum_node(&|_| false); 之后立即结束。

这不是我的问题。

self的第一次调用结束后,对enum_node进行更改的唯一方法是通过返回值即enum_node进行更改,该值是不可变的。为什么编译器继续将借贷视为可变的,这是合逻辑的吗?

我如何理解编译器的这种行为?

0 个答案:

没有答案