不能借用为可变的,从借用的值 [duplicate] 获取可变引用

Cannot borrow as mutable, getting a mutable reference from a borrowed value [duplicate]

提问人:Danilo Souza Morães 提问时间:12/28/2022 更新时间:12/28/2022 访问量:329

问:

我正在关注另一篇文章:了解 Rust 'Rc<RefCell<_>>',其中 op 尝试用 Box 实现一棵树并成功做到了,但随后尝试使用 Rc 和 RefCell 实现它并发现了问题。接受的答案可以编译,但不起作用,因为它不会向根目录添加节点。我尝试稍微更新一下接受的答案,试图让它工作,但无法做到。基本上,我试图在循环中获取可变引用,但我不能,因为我钻了一个不可变的引用。但是,如果一个 borrow_mut() 我得到该值是一个私有字段,那么我假设如果它是可变引用,我无法访问包含值的任何属性?

我应该怎么做才能使此代码正常工作?

use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt;

#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
    root: Option<Box<NodeBox<T>>>,
}

#[derive(Debug, Clone)]
struct NodeBox<T> {
    value: T,
    left: Option<Box<NodeBox<T>>>,
    right: Option<Box<NodeBox<T>>>,
}

impl<T: Ord> TreeBox<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        while let Option::Some(current_node) = node {
            match current_node.value.cmp(&value) {
                Ordering::Less => node = &mut current_node.right,
                Ordering::Equal => return false,
                Ordering::Greater => node = &mut current_node.left,
            }
        }

        *node = Option::Some(Box::new(NodeBox {
            value,
            left: Option::None,
            right: Option::None,
        }));

        return true;
    }
}

#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
    root: Option<Rc<RefCell<Node<T>>>>,
}

#[derive(Debug, Clone, PartialEq)]
struct Node<T> {
    value: T,
    left: Option<Rc<RefCell<Node<T>>>>,
    right: Option<Rc<RefCell<Node<T>>>>,
}

impl<T: Ord + fmt::Debug> Tree<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        while let Some(current_node) = node {
            let current_node = current_node.borrow();
            let cmp = current_node.value.cmp(&value);
            let new_node = match cmp {
                Ordering::Less => &mut current_node.left,
                Ordering::Equal => return false,
                Ordering::Greater => &mut current_node.right,
            };
            node = new_node;
        }

        // let mut node = &mut node;
        *node = Some(Rc::new(RefCell::new(Node {
            value,
            left: None,
            right: None,
        })));

        println!("node: {:?}", node);
        true
    }

}

fn main() {

    let mut tree_box = TreeBox::new();
    tree_box.insert(1);
    tree_box.insert(2);
    tree_box.insert(3);

    let mut tree = Tree::new();
    tree.insert(1);
    tree.insert(2);
    tree.insert(3);

    println!("TreeBox: {:?}", tree_box);
    println!("Tree: {:?}", tree);
}
不变性 可变

评论

1赞 cafce25 12/28/2022
因为你错误地导入了你使用而不是你希望通过使用获得什么?这不是它的应用程序之一。BorrowMutBorrowMut::borrow_mutRefCell::borrow_mutRc<RefCell<T>>Box<T>

答:

1赞 Rubens Brandão 12/28/2022 #1

接受的答案可以编译,但不起作用,因为它不会向根目录添加节点。

你是对的,并修复原始解决方案,这里有一个正确添加根节点的版本:

    pub fn insert(&mut self, value: T) -> bool {
        //if no root, just create one
        let mut node = if let Some(root) = &self.root {
            Rc::clone(root)
        } else {
            self.root = Some(Rc::new(RefCell::new(Node {
                value,
                left: None,
                right: None,
            })));
            return true;
        };

        loop {
            let current_node = Rc::clone(&node);
            let mut current_node = RefCell::borrow_mut(&current_node);
            let cmp = current_node.value.cmp(&value);
            let next_node = match cmp {
                Ordering::Less => &mut current_node.left,
                Ordering::Equal => return false,
                Ordering::Greater => &mut current_node.right,
            };
            if let Some(next_node) = next_node {
                node = Rc::clone(next_node);
            } else {
                *next_node = Some(Rc::new(RefCell::new(Node {
                    value,
                    left: None,
                    right: None,
                })));

                println!("node: {:?}", node);
                return true;
            }
        }
    }

基本上,我试图在循环中获取可变引用,但我不能,因为我钻了一个不可变的引用。

问题略有不同。发生的情况是,你不能在这棵树上行走,至少不能像这样交互,因为当你使用它时,需要保留这种结构的“借用”。您的实现会在每个循环后释放“借用”。Rc<RefCell>

但是,如果一个 borrow_mut() 我得到的值是一个私有字段,所以我是 假设我无法访问包含值的任何属性,如果是 可变引用?

不是真的,这里发生的事情是你没有调用返回 的函数,你实际上是在调用返回的函数。通过访问,您正在尝试从 而不是 访问私有字段。RefCell::borrow_mutRefMut<Node><Rc as BorrowMut>::borrow_mut&mut RefMut<...>valuevalueRefCellNode

请注意,在我的实现中,我显式调用了 ,这解决了这个问题。RefCell::borrow_mut

评论

2赞 Chayim Friedman 12/28/2022
我认为这个答案应该移到原来的问题。
0赞 kmdreko 12/28/2022
同意,特别是因为现有的问题最好向其他读者提出,但现有的答案是有缺陷的。
0赞 Danilo Souza Morães 12/28/2022
我理解您通过循环迭代而不是可变引用传递 Rc 的自有实例的解决方案,但是我无法通过迭代借用可变吗?原始帖子的 Box 实现就是这样做的。为什么会这样?
0赞 Rubens Brandão 12/28/2022
持有可变引用与使用 .这是因为只有当你在变量中保存借来的值()时,你才能访问RefCell中的数据,如果你有一个递归调用,而不是循环,你可以这样做。RefCell::borrow_mutRef/RefMut
0赞 Danilo Souza Morães 12/28/2022
但是我克隆了,突然间我能够将这个 Rc 对象传递到下一个迭代,即使前一个borrow_mut被丢弃了。为什么我可以在 Rc 中保留以前borrow_mut的引用?为什么当 RefMut 被丢弃时,我们不会失去对 Rc 内部对象的访问权限?&mut current_node.left