【问题标题】:Borrow pointer errors recursively traversing tree [duplicate]借用指针错误递归遍历树[重复]
【发布时间】:2015-02-27 14:13:04
【问题描述】:

为了学习 Rust,我正在实现一个 AVL 树/字典。要插入一个新元素,我会下降到树中,直到找到可以插入它的节点。不幸的是,它抱怨了一些借用指针的问题,我在破译它们时遇到了麻烦。

我已经强调了发生的位置和错误。

enum AVLTree<T, U> {
    Tree(T, U, Box<AVLTree<T, U>>, Box<AVLTree<T, U>>),
    Empty,
}

impl<T, U> AVLTree<T, U>
    where T: PartialOrd + PartialEq + Copy,
          U: Copy
{
    fn insert_element(&mut self, key: T, val: U) {
        let new_node = AVLTree::Tree(key, val, Box::new(AVLTree::Empty), Box::new(AVLTree::Empty));

        if let AVLTree::Empty = *self {
            *self = new_node;
            return;
        }

        let mut at = self;
        loop {
            match at {
                &mut AVLTree::Tree(key2, _, ref mut left, ref mut right) => {
                    //                      ^~~~~~~~~~~~
                    // error: cannot borrow `at.2` as mutable more than once at a time
                    //                                    ^~~~~~~~~~~~~
                    // error: cannot borrow `at.3` as mutable more than once at a time
                    if key < key2 {
                        if let AVLTree::Empty = **left {
                            *left = Box::new(new_node);
                            break;
                        }
                        at = &mut **left;
                        // error: cannot assign to `at` because it is borrowed
                    } else {
                        if let AVLTree::Empty = **right {
                            *right = Box::new(new_node);
                            break;
                        }
                        at = &mut **right;
                        // error: cannot assign to `at` because it is borrowed
                    }
                }
                &mut AVLTree::Empty => unreachable!(),
            }
        }
        // Do something
    }
}

解构at为什么要借用呢?为什么编译器会抱怨多个可变借用,而这种情况永远不会发生?如何编写此代码以避免此类错误?

【问题讨论】:

  • 提问时请考虑创建MCVE。这有助于您了解问题的具体部分,也有助于回答者更快地理解问题。这是example for this case
  • 感谢您的提示,我以后会记住的。 (我不经常问问题,所以我有点尴尬)
  • 别担心!我们都必须从某个地方开始。 ^_^

标签: rust


【解决方案1】:

这似乎是借用检查器的一个弱点,并且可能是一个错误。问题是您在匹配中借用at 然后对其进行修改。不幸的是,编译器没有看到循环内和循环外的at 在概念上是不同的。但是,我们可以使它们明显不同:

enum AVLTree {
    Tree(Box<AVLTree>),
    Empty,
}

impl AVLTree {
    fn insert_element(&mut self) {
        let mut at = self;
        loop {
            let tmp_at = at; // Main change
            match tmp_at {
                &mut AVLTree::Tree(ref mut left) => {
                    at = &mut **left;
                }
                &mut AVLTree::Empty => unreachable!()
            }
        }
    }
}

fn main() {}

这里,我们将可变借用从at转移到tmp_at,然后转移到left,再转移回at

更漂亮的选择可能是使用新范围:

fn insert_element(&mut self) {
    let mut at = self;
    loop {
        match {at} { // Main change
            &mut AVLTree::Tree(ref mut left) => {
                at = &mut **left;
            }
            &mut AVLTree::Empty => unreachable!(),
        }
    }
}

【讨论】:

  • 我不确定这真的是一个错误,因为借用检查没有声称它没有误报,但这是不受欢迎的行为。它有一个问题,但它并没有真正得到太多关注。 github.com/rust-lang/rust/issues/17462
猜你喜欢
  • 2018-07-12
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多