我正在学习Rust并尝试编写一个双向链表。但是,我已经陷入了典型的迭代遍历实现。我得到的印象是借用检查器/掉落检查器太严格,并且当它从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
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^ temporary value does not live long enough
23 | }
| - temporary value dropped here while still borrowed
...
28 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
使用NLL
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^
| |
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
23 | }
| -
| |
| 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<'_, LinkedNode<T>>`
|
= note: consider using a `let` binding to create a longer lived value
= note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
我真的很感激这个问题的迭代解决方案(非递归)。
答案 0 :(得分:1)
这是一个较小的复制品,我相信也会出现同样的问题:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
当我读到它时:
foo.borrow()
返回cell::Ref
,一种智能指针。在这种情况下,智能指针的作用类似于&Option<i32>
。as_ref()
创建一个Option<&i32>
,其内部引用与智能指针的生命周期相同。Option
被丢弃,只产生&i32
,但仍有智能指针的生命周期。值得注意的是,智能指针Ref
仅持续该语句,但代码尝试将引用返回到Ref
,这将超过该语句。
通常,解决方案是做这样的事情:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
这使智能指针保持更长时间,只要foo_borrow
(代表借用本身)存在,就可以使引用的生命周期有效。
在循环的情况下,你可以做的事情并不多,因为你基本上想要借用每个前一个节点,直到你到达下一个节点。
答案 1 :(得分:1)
您可以克隆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;
}