Rust 遍历中RefCell借用的循环引用
我正在学习Rust并尝试编写一个双链接列表。然而,我已经陷入了一个典型的迭代遍历实现中。我得到的印象是,借用检查器/放置检查器过于严格,当借用器从Rust 遍历中RefCell借用的循环引用,rust,smart-pointers,lifetime,borrowing,interior-mutability,Rust,Smart Pointers,Lifetime,Borrowing,Interior Mutability,我正在学习Rust并尝试编写一个双链接列表。然而,我已经陷入了一个典型的迭代遍历实现中。我得到的印象是,借用检查器/放置检查器过于严格,当借用器从RefCell跨越函数边界时,无法推断其正确的使用寿命。我需要重复设置一个变量绑定(curr,在本例中)以借用其当前内容: use std::cell::RefCell; use std::rc::Rc; pub struct LinkedList<T> { head: Option<Rc<RefCell<Lin
RefCell
跨越函数边界时,无法推断其正确的使用寿命。我需要重复设置一个变量绑定(curr
,在本例中)以借用其当前内容:
use std::cell::RefCell;
use std::rc::Rc;
pub struct LinkedList<T> {
head: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
struct LinkedNode<T> {
value: T,
next: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
impl<T> LinkedList<T> {
pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
// ... some logic ...
// This is the traversal that fails to compile.
let mut curr = self.head.as_ref().unwrap();
for _ in 1..idx {
curr = curr.borrow().next.as_ref().unwrap()
}
// I want to use curr here.
// ...
unimplemented!()
}
}
使用NLL
错误[E0716]:借用时丢弃的临时值
-->src/lib.rs:22:20
|
22 | curr=curr.borrow().next.as|ref().unwrap()
| ^^^^^^^^^^^^^
| |
|创建在仍在使用时释放的临时文件
|在此处创建具有借用权限的临时文件。。。
23 | }
| -
| |
|临时值在此语句末尾被释放
| ... 这里可能会用到借阅,当临时文件被删除并运行类型为'std::cell::Ref的析构函数时,这里有一个较小的复制,我相信它显示了相同的问题:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
正如我读到的:
foo.borrow()
返回一种智能指针。在这种情况下,智能指针的作用类似于一个&选项
as_ref()
创建一个选项,其中内部引用与智能指针具有相同的生存期
选项
被丢弃,只产生一个&i32
,仍然具有智能指针的生命周期
值得注意的是,智能指针Ref
仅在语句中有效,但代码尝试将引用返回到Ref
中,该引用将在语句中有效
一般来说,解决方案是这样做:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
这会延长智能指针的使用时间,从而允许引用的生存期在foo\u borrow
(表示借用本身)存在的时间内有效
在循环的情况下,没有什么可以做的,因为在到达下一个节点之前,您基本上希望借用前一个节点。您可以克隆Rc
,以避免生存期问题:
let mut curr = self.head.as_ref().unwrap().clone();
for _ in 1..idx {
let t = curr.borrow().next.as_ref().unwrap().clone();
curr = t;
}
注意:借用检查器不太严格,它可以防止此处出现锯齿。如果不是这样,您可能会有易变性+别名,从而导致崩溃或内存损坏。@MatthieuM。这里哪里会出现别名?你有机会阅读吗?@Shepmaster:如果你不借用self
就可以获得curr
,那么是什么阻止你在同一个方法体中再次获得curr
?没有什么。通过获取RefCell::borrow
以仅借出在其结果生命周期内有效的引用,可以动态防止这种情况。谢谢您的回答。你是说在循环中没有办法做到这一点吗?我不确定你的例子是否能解决我的问题。@Tsukki不会说不行,但我不知道。当你递归地做这件事时,我假设有一个未偿还借款的隐式层次结构,允许它继续进行。谢谢,这成功了!但是,当我需要从下面几行中的curr
借用mut时,我必须执行let next=curr.borrow_mut().next.take();匹配下一个{…}
而不是简单地匹配curr.borrow_mut().next.take(){…}
。编译器并不试图推断出什么。