Memory management 可变二叉树上的递归:`已借用:借用MuterError`

Memory management 可变二叉树上的递归:`已借用:借用MuterError`,memory-management,rust,borrowing,Memory Management,Rust,Borrowing,我从排序节点的Vec开始,然后使用此排序将这些节点链接到二叉树中,然后返回基本结构 //测试名称 #[衍生(克隆)] 结构{ 家长:选择, 上标:期权, 下标:选项, 身高:u32, 中心:u32, 符号:VecDeque } 最后是由上面的Structs组成的二叉树。在这一点上,这些Structs是唯一拥有的,因此我想我可以从使用Rc转换为RefCell(认为Box由于内部易变性而不起作用),但我不确定这如何或是否有助于解决我遇到的问题 在此之后,我需要以一种新颖的方式迭代结构s,并通过调用

我从排序节点的
Vec
开始,然后使用此排序将这些节点链接到二叉树中,然后返回基本结构

//测试名称
#[衍生(克隆)]
结构{
家长:选择,
上标:期权,
下标:选项,
身高:u32,
中心:u32,
符号:VecDeque
}
最后是由上面的
Struct
s组成的二叉树。在这一点上,这些
Struct
s是唯一拥有的,因此我想我可以从使用
Rc
转换为
RefCell
(认为
Box
由于内部易变性而不起作用),但我不确定这如何或是否有助于解决我遇到的问题

在此之后,我需要以一种新颖的方式迭代
结构
s,并通过调用
.pop_front()
在整个递归过程中变异属于各种
结构
的各种
符号

我当前的实现这样做会导致
线程'main'的各种实例在'ready-followed:followemuterror'
上惊慌失措

游乐场连接:

它的功能(请原谅复杂的逻辑):

fn遍历脚本(行:Rc){
如果让某些(上标_行)=&row.borrow().superscript{
如果让一些(上标_符号)=上标_行。借用().symbols.front(){
如果让某些(当前_行_符号)=row.borrow().symbols.front(){
如果上标_符号<当前_行_符号{
println!(“^{{{}”,上标*符号);
上标_row.borrow_mut().symbols.pop_front();
遍历_脚本(Rc::clone(上标_行));
}
}
否则{
println!(“^{{{}”,上标*符号);
上标_row.borrow_mut().symbols.pop_front();
遍历_脚本(Rc::clone(上标_行));
}
}
}
如果让某些(下标_行)=&row.borrow().subscript{
如果let Some(subscript_symbol)=subscript_row.borrow().symbols.front(){
如果让某些(当前_行_符号)=row.borrow().symbols.front(){
如果下标符号<当前行符号{
打印!(“{{{{}”,下标*符号);
下标行。借用行().symbols.pop_front();
遍历_脚本(Rc::clone(下标_行));
}
}
否则{
打印!(“{{{{}”,下标*符号);
下标行。借用行().symbols.pop_front();
遍历_脚本(Rc::clone(下标_行));
}
}
}
如果让某些(当前_行_符号)=row.borrow().symbols.front(){
如果让某些(父行)=&row.borrow().parent{
如果let Some(parent_symbol)=parent_row.borrow().symbols.front(){
如果当前行符号<父行符号{
打印!({},*当前行符号);
row.borrow_mut().symbols.pop_front();
遍历_脚本(Rc::clone(&row));
}
}
}
否则{
打印!({},*当前行符号);
row.borrow_mut().symbols.pop_front();
遍历_脚本(Rc::clone(&row));
}
}
如果让某些(父行)=&row.borrow().parent{
如果let Some(parent_symbol)=parent_row.borrow().symbols.front(){
打印!(“}}{},*父字符);
row.borrow_mut().symbols.pop_front();
遍历_脚本(Rc::clone(父_行));
}否则{
打印!(“}”);
遍历_脚本(Rc::clone(父_行));
}
}
}
我已经考虑过使用
Arc
来代替遍历,但是考虑到它不是多线程的,我不认为这是必要的

我想我可能错过了一个相对简单的想法,我真的非常感谢任何帮助


如果我的问题遗漏了什么,请留下一条评论,我会尝试添加。

当你在
RefCell
上调用
Ref
RefMut
时,一个守卫对象(
Ref
RefMut
)创建的,只要内部值存在,就授予对其的访问权限。此防护将锁定
RefCell
,直到它超出范围并被销毁。让我们看一下
遍历脚本的一部分:

if let Some(superscript_row) = &row.borrow().superscript { // row is borrowed
    if let Some(superscript_symbol) = superscript_row.borrow().symbols.front() { // superscript_row is borrowed
        if let Some(current_row_symbol) = row.borrow().symbols.front() { // row is borrowed again
            if superscript_symbol < current_row_symbol {
                println!("^{{{}", *superscript_symbol);
                superscript_row.borrow_mut().symbols.pop_front(); // superscript_row is borrowed mutably (ERROR)
                traverse_scripts(Rc::clone(superscript_row)); // recursive call while row and superscript_row are borrowed (ERROR)
            }
        } else {
            println!("^{{{}", *superscript_symbol);
            superscript_row.borrow_mut().symbols.pop_front(); // superscript_row is borrowed mutably (ERROR)
            traverse_scripts(Rc::clone(superscript_row)); // recursive call while row and superscript_row are borrowed (ERROR)
        } // row is no longer borrowed twice
    } // superscript_row is no longer borrowed
} // row is no longer borrowed


这看起来很复杂,因为它很复杂。在对数据结构进行变异的同时遍历数据结构是常见的错误源(在大多数语言中,而不仅仅是Rust)。看起来,至少在
遍历脚本
中,需要变异的唯一原因是调用
符号
上的
弹出前端
,因此,如果您可以重新设计数据结构,使
符号
位于
参考单元格
,那么您可以只使用
引用进行遍历,这将非常复杂另一种常见的方法是编写返回新数据结构的函数,而不是对它们进行适当的修改。

此时,这些
结构是唯一拥有的:可以创建具有唯一所有权的树,但事实并非如此:每个节点可能由其子节点中的父链接以及子节点中的子链接拥有ts parent。如果你想切换到
,你必须删除父链接。
互斥
也不会有帮助,顺便说一句,
锁定
方法的工作方式与
RefCell
上的
借用
的工作方式相同。因此,你最终会遇到同样的问题。谢谢!(在对我的逻辑进行了一些重构之后,它工作了)@JonathanWoollett light您还可以通过将每个嵌套的
if let…if…else
折叠为单个
if
,使此代码更简单,因为内部
if
和外部
else
是相同的:。代码中存在一些不对称
{ // This scope will constrain the lifetime of row_ref
    let row_ref = row.borrow();
    if let Some(superscript_row) = &row_ref.superscript {
        let mut child = superscript_row.borrow_mut(); // use borrow_mut here because we know we'll need it later
        if let Some(superscript_symbol) = child.symbols.front() {
            if let Some(current_row_symbol) = row_ref.symbols.front() {
                if superscript_symbol < current_row_symbol {
                    println!("^{{{}", *superscript_symbol);
                    child.symbols.pop_front();
                    drop(child); // child is no longer needed, so drop it before recursing
                    // Since superscript_row borrows from row_ref, we must Rc::clone it before
                    // dropping row_ref so that we can still pass it to traverse_scripts.
                    let superscript_row = Rc::clone(superscript_row);
                    drop(row_ref); // row_ref is no longer needed, so drop it before recursing
                    traverse_scripts(superscript_row);
                }
            } else {
                println!("^{{{}", *superscript_symbol);
                child.symbols.pop_front();
                // see comments earlier
                drop(child);
                let superscript_row = Rc::clone(superscript_row);
                drop(row_ref);
                traverse_scripts(superscript_row);
            }
        }
    } // child is dropped here (if it wasn't already). superscript_row is no longer borrowed
} // row_ref is dropped here (if it wasn't already). row is no longer borrowed