我具有以下树结构:
use std::cell::RefCell;
use std::rc::Rc;
use std::cmp;
use std::cmp::Ordering;
type AVLTree<T> = Option<Rc<RefCell<TreeNode<T>>>>;
#[derive(Debug, PartialEq, Clone)]
struct TreeSet<T: Ord> {
root: AVLTree<T>,
}
impl<T: Ord> TreeSet<T> {
fn new() -> Self {
Self {
root: None
}
}
fn insert(&mut self, value: T) -> bool {
let current_tree = &mut self.root;
while let Some(current_node) = current_tree {
let node_key = ¤t_node.borrow().key;
match node_key.cmp(&value) {
Ordering::Less => { let current_tree = &mut current_node.borrow_mut().right; },
Ordering::Equal => {
return false;
}
Ordering::Greater => { let current_tree = &mut current_node.borrow_mut().left; },
}
}
*current_tree = Some(Rc::new(RefCell::new(TreeNode {
key: value,
left: None,
right: None,
parent: None
})));
true
}
}
#[derive(Clone, Debug, PartialEq)]
struct TreeNode<T: Ord> {
pub key: T,
pub parent: AVLTree<T>,
left: AVLTree<T>,
right: AVLTree<T>,
}
fn main() {
let mut new_avl_tree: TreeSet<u32> = TreeSet::new();
new_avl_tree.insert(3);
new_avl_tree.insert(5);
println!("Tree: {:#?}", &new_avl_tree);
}
使用cargo build
构建是可以的,但是当我运行cargo run
时,出现以下错误:
线程“主”对“已借用:BorrowMutError”感到恐慌,src \ libcore \ result.rs:1165:5
注意:使用
RUST_BACKTRACE=1
环境变量运行以显示回溯。错误:流程没有成功退出:
target\debug\avl-tree.exe
(退出代码:101)
如果我只打电话给insert(3)
,就可以了,我的树可以正确打印了。但是,如果我在insert(5)
之后insert(3)
,则会收到该错误。
我该如何解决?
答案 0 :(得分:1)
由于语言中的内存安全规则,对于新手来说,手动实现诸如链表,树,图之类的数据结构不是任务。我建议您阅读Too Many Linked Lists教程,该教程讨论了如何以正确的方式实现Rust的安全列表和不安全链接列表。
也请阅读有关name shadowing的信息。 您的错误是,在一个循环中,您尝试借用可变的东西,而这些东西已经借来的是不可变的。
let node_key = ¤t_node.borrow().key; // Borrow as immutable
match node_key.cmp(&value) {
Ordering::Less => { let current_tree = &mut current_node.borrow_mut().right; }, // Create a binding which will be immediately deleted and borrow as mutable.
我建议您阅读Rust book以学习防锈。
答案 1 :(得分:0)
首先让我们更正您的算法。以下几行是错误的:
let current_tree = &mut current_node.borrow_mut().right;
...
let current_tree = &mut current_node.borrow_mut().left;
两者都不会将值重新分配给current_tree
,而是创建一个新的(未使用的)值(@Inline将其称为“名称阴影”)。删除let
并制作current_tree
mut
。
现在,我们收到编译器错误temporary value dropped while borrowed
。可能是编译器错误消息确实误导了您。它告诉您使用let
来延长生命周期,如果您在相同的范围内使用结果,这是正确的,但是不允许让生命周期超出范围。
问题是您无法传递对循环所拥有的值的引用(如current_node.borrow_mut.right
)。因此,最好使用current_tree
作为拥有的变量。可悲的是,这意味着代码中的许多巧妙技巧将不再起作用。
代码中的另一个问题是多重借用问题(您最初的运行时警告与此有关)。您不能在没有惊慌的情况下在同一borrow()
上呼叫borrow_mut()
和RefCell
(这是RefCell
的目的)。
因此,在找到代码中的问题之后,我对如何编写代码产生了兴趣。现在,它已经写好了,我认为共享它是公平的: fn insert(&mut self,value:T)-> bool { 如果让None = self.root { self.root = TreeSet :: root(value); 返回true; } 让mut current_tree = self.root.clone();
while let Some(current_node) = current_tree {
let mut borrowed_node = current_node.borrow_mut();
match borrowed_node.key.cmp(&value) {
Ordering::Less => {
if let Some(next_node) = &borrowed_node.right {
current_tree = Some(next_node.clone());
} else {
borrowed_node.right = current_node.child(value);
return true;
}
}
Ordering::Equal => {
return false;
}
Ordering::Greater => {
if let Some(next_node) = &borrowed_node.left {
current_tree = Some(next_node.clone());
} else {
borrowed_node.left = current_node.child(value);
return true;
}
}
};
}
true
}
//...
trait NewChild<T: Ord> {
fn child(&self, value: T) -> AVLTree<T>;
}
impl<T: Ord> NewChild<T> for Rc<RefCell<TreeNode<T>>> {
fn child(&self, value: T) -> AVLTree<T> {
Some(Rc::new(RefCell::new(TreeNode {
key: value,
left: None,
right: None,
parent: Some(self.clone()),
})))
}
}
一个人必须编写两种方法child(value:T)
和root(value:T)
进行编译。