借用检查器不允许从树遍历函数返回可变引用

时间:2017-10-24 06:42:32

标签: rust borrow-checker borrowing

我需要在树中找到具有最大值的节点,假设子节点的值总是大于拥有节点的值,然后修改它:

error[E0499]: cannot borrow `node.nodes` as mutable more than once at a time
  --> src/main.rs:13:19
   |
12 |     let mut max: Option<&mut Node> = Some(node);
   |                                           ---- first mutable borrow occurs here
13 |     for n in &mut node.nodes {
   |                   ^^^^^^^^^^ second mutable borrow occurs here
...
20 | }
   | - first borrow ends here

借用检查器返回此错误:

mut

如果我从find_max移除find_max,它就会有效,但我看不出如何从find_max返回可变引用。

重要的是#include <stdio.h> void triangle(int size); void triangle_aux(int size, int n); int main() { int base_length; printf("Enter the base length:\n"); scanf("%d",&base_length); if(base_length < 1 || base_length > 79 || base_length%2 == 0) printf("The maximum base length permitted is 79 and has to be an odd number.\nPlease try again with a valid number.\nThank You!!!"); else triangle(base_length); } void triangle(int size) { triangle_aux(size, 0); } void triangle_aux(int size, int n) { int i; for(i=0; i<n; i++) printf(" "); if(n==size/2) printf("*\n"); else { for(i=n; i<size-n; i++) printf("X"); printf("\n"); triangle_aux(size, n+1); } } 本身不会修改任何内容。它只是搜索一个合适的节点。

3 个答案:

答案 0 :(得分:4)

不需要使用unsafe

fn find_max(node: &mut Node, val: usize) -> Option<&mut Node> {
    if node.val < val {
        return None;
    }

    if node.nodes.is_empty() {
        return Some(node);
    }

    let mut max_val = node.val;
    let mut max = None;
    for n in &mut node.nodes {
        if let Some(m) = find_max(n, max_val) {
            max_val = m.val;
            max = Some(m);
        }
    }
    max
}

答案 1 :(得分:0)

似乎是unsafe合理的罕见案例之一。

在这种情况下,通常的方法是用不可变引用替换可变引用并使用内部可变性。但是在这种情况下,我们需要递归地borrow() RefCell,并且即使在函数返回之后也以某种方式使它们保持活动状态。

考虑到问题不是由操作固有的不安全引起的,而是由于Rust借用检查器的限制,使用unsafe是有意义的。请记住,虽然我有理由确定以下代码是安全的,但最好还是等待评论或其他解决方案。

fn find_max(node: &mut Node, val: usize) -> Option<&mut Node> {
    if node.val < val {
        return None;
    }
    let mut max = None;
    let mut max_val = node.val;
    // keep reference around as a pointer
    let node_ptr = node as *mut Node;
    // `{ node }` moves the reference instead of reborrowing it
    // so we can recreate it later with no risk of undefined behavior
    for n in &mut { node }.nodes {
        if let Some(m) = find_max(n, max_val) {
            max_val = m.val;
            max = Some(m);
        }
    }
    max.or_else(
        // the closure is executed only when `max == None`
        // and `node` was moved out earlier in `{node}`
        // therefore there's no active mutable references reachable thru recreated reference
        // function signature ensures that lifetime of the returned reference is ok
        // thus we can safely recreate the same mutable reference we received in `node`
        || unsafe { node_ptr.as_mut() }
    )
}

答案 2 :(得分:-2)

你可以用*代替&amp; mut来deref。但是[Node]没有在编译时知道的常量大小