遍历列表时,借用的RefCell的持续时间不够长 [英] Borrowed RefCell does not last long enough when iterating over a list
问题描述
我正在尝试实现一个链接列表,以了解Rust中的智能指针.我定义了一个 Node
:
I'm trying to implement a linked list to understand smart pointers in Rust. I defined a Node
:
use std::{cell::RefCell, rc::Rc};
struct Node {
val: i32,
next: Option<Rc<RefCell<Node>>>,
}
并像
fn iterate(node: Option<&Rc<RefCell<Node>>>) -> Vec<i32> {
let mut p = node;
let mut result = vec![];
loop {
if p.is_none() {
break;
}
result.push(p.as_ref().unwrap().borrow().val);
p = p.as_ref().unwrap().borrow().next.as_ref();
}
result
}
编译器报告错误:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:27:13
|
27 | p = p.as_ref().unwrap().borrow().next.as_ref();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| | |
| | 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 `std::cell::Ref<'_, Node>`
| 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
发生了什么事?我们不能使用引用来迭代这样定义的节点吗?
What happened? Can't we use a reference to iterate on a node defined this way?
推荐答案
您需要克隆 Rc
:
use std::cell::RefCell;
use std::rc::Rc;
struct Node {
val: i32,
next: Option<Rc<RefCell<Node>>>,
}
fn iterate(node: Option<Rc<RefCell<Node>>>) -> Vec<i32> {
let mut p = node;
let mut result = vec![];
loop {
let node = match p {
None => break,
Some(ref n) => Rc::clone(n), // Clone the Rc
};
result.push(node.as_ref().borrow().val); //works because val is Copy
p = match node.borrow().next {
None => None,
Some(ref next) => Some(Rc::clone(next)), //clone the Rc
};
}
result
}
fn main() {
let node = Some(Rc::new(RefCell::new(Node {
val: 0,
next: Some(Rc::new(RefCell::new(Node { val: 1, next: None }))),
})));
let result = iterate(node);
print!("{:?}", result)
}
这是必要的,因为您试图在需要更长寿命的上下文中使用寿命较短的变量.循环迭代后,将删除 p.as_ref().unwrap().borrow()
的结果,但您尝试在下一个循环中使用其成员(这称为"免费使用后
",Rust的设计目标之一就是防止这种情况发生.)
This is necessary because you are trying to use a variable with a shorter lifespan in a context that requires a longer lifespan. The result of p.as_ref().unwrap().borrow()
is dropped (i.e. freed, de-allocated) after the loop iteration, but you are trying to use its members in the next loop (this is called use after free
and one of the design goals of Rust is to prevent that).
问题在于借用不拥有对象.如果您想在下一个循环中使用 next
作为 p
,那么 p
将必须拥有该对象.这可以通过 Rc
(即引用计数")实现,并允许单个线程中有多个所有者.
The issue is that borrows do not own the object. If you want to use the next
as p
in the next loop, then p
will have to own the object. This can be achieved with Rc
(i.e. 'reference counted') and allows for multiple owners in a single thread.
如果
Node :: next
的定义是Option< Box< RefCell< Node>>>
,该如何遍历此列表呢?
What if the definition of
Node::next
isOption<Box<RefCell<Node>>>
, how to iterate over this list?
是的,我也对
RefCell
感到非常困惑,如果没有RefCell
,我们只能使用引用来遍历列表,但是如果使用RefCell
.我什至尝试添加Ref
的向量来保存引用,但仍然无法成功.
Yes, I'm also very confused with
RefCell
, withoutRefCell
we can iterate over list using reference only, but will fail withRefCell
. I even tried to add a vector ofRef
to save the reference, but still can not success.
如果您放下 RefCell
,则可以这样进行迭代:
If you drop the RefCell
you can iterate it like this:
struct Node {
val: i32,
next: Option<Box<Node>>,
}
fn iterate(node: Option<Box<Node>>) -> Vec<i32> {
let mut result = vec![];
let mut next = node.as_ref().map(|n| &**n);
while let Some(n) = next.take() {
result.push(n.val);
let x = n.next.as_ref().map(|n| &**n);
next = x;
}
result
}
fn main() {
let node = Some(Box::new(Node {
val: 0,
next: Some(Box::new(Node { val: 1, next: None })),
}));
let result = iterate(node);
print!("{:?}", result)
}
也许也可以使用 RefCell
,但是我无法解决生命周期问题.
Maybe it's possible with a RefCell
as well, but I was not able to work around the lifetime issues.
这篇关于遍历列表时,借用的RefCell的持续时间不够长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!