![](/img/trans.png)
[英]'cannot return reference to temporary value' using Option<Rc<RefCell<T>>>
[英]How to handle "temporary value dropped" error when adapting Box-based tree structure to Rc+RefCell?
我创建了一棵树,其类型定义类似于:
#[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;
}
}
这非常有效,我对实施非常满意。 但是我想将每个节点的引用存储到它的父节点。 经过一些研究,我在 Rust 书中找到了描述使用RefCell
和Weak
结构的实现的部分。
有了这些知识,我的计划是更新上面的例子。 我的想法是我可以将Box<...>
替换为Rc<RefCell<..>>
。 我的想法是,这些类型非常相似,因为它们都存储对某些数据结构的引用,唯一的区别是可以有多个Rc<RefCell<..>>
指向该数据结构。 我将我的实现更改为:
#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
root: Option<Rc<RefCell<Node<T>>>>,
}
#[derive(Debug, Clone)]
struct Node<T> {
value: T,
left: Option<Rc<RefCell<Node<T>>>>,
right: Option<Rc<RefCell<Node<T>>>>,
}
impl<T: Ord> Tree<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 {
let cmp = current_node.borrow().value.cmp(&value);
match cmp {
Ordering::Less => node = &mut current_node.borrow_mut().right,
Ordering::Equal => return false,
Ordering::Greater => node = &mut current_node.borrow_mut().left,
};
}
*node = Option::Some(Rc::new(RefCell::new(Node {
value,
left: Option::None,
right: Option::None,
})));
return true;
}
}
但是,这个更新的示例无法编译:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:28:47
|
28 | Ordering::Less => node = &mut current_node.borrow_mut().right,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ -
| | |
| | temporary value is freed at the end of this statement
| | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `RefMut<'_, Node<T>>`
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
|
= note: consider using a `let` binding to create a longer lived value
这两个示例都可以在playground上找到。
我的示例是错误的,还是我对Rc<RefCell<_>>
仍然不太了解?
所以,你有几个问题。 第一个是你试图引用一个Option
包含一个生命周期很短的值,因为它与RefCell
上的 borrow borrow()
相关联。 (当borrow
到位时,您还试图借用borrow_mut
,这会引起恐慌。)幸运的是, Rc
使得获取对Rc
的引用的所有权变得便宜且容易(这就是重点),所以这个问题可以通过存储来解决Option
,而不是&Option
,并且自由地克隆了包含的Rc
。 我们使用Option::as_ref
将&Option<Rc<_>>
转换为Option<&Rc<_>>
,然后通过映射Rc::clone
将其转换为Option<Rc<_>>
。
pub fn insert(&mut self, value: T) -> bool {
let mut node = self.root.as_ref().map(Rc::clone);
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 => ¤t_node.left,
Ordering::Equal => return false,
Ordering::Greater => ¤t_node.right,
};
node = new_node.as_ref().map(Rc::clone);
}
let node = &mut node;
*node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
true
}
虽然原来的答案是正确的,但示例中的代码不起作用,因为它忘记添加根节点。
这些是解决此问题的两种选择:
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(¤t_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;
}
}
}
递归解决方案:
impl<T: Ord + fmt::Debug> Tree<T> {
fn new() -> Self {
Self { root: None }
}
pub fn insert(&mut self, value: T) -> bool {
//if no root, just create one
if let Some(root) = &self.root {
let mut root = RefCell::borrow_mut(&root);
root.insert(value)
} else {
self.root = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
true
}
}
}
impl<T: Ord + fmt::Debug> Node<T> {
fn insert(&mut self, value: T) -> bool {
let node = match self.value.cmp(&value) {
Ordering::Less => &mut self.left,
Ordering::Equal => return false,
Ordering::Greater => &mut self.right,
};
//if the node is empty, add to it, otherwise check deeper
if let Some(node) = node {
let mut node = RefCell::borrow_mut(node);
node.insert(value)
} else {
*node = Some(Rc::new(RefCell::new(Node {
value,
left: None,
right: None,
})));
println!("node: {:?}", node);
true
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.