rust - 如何获得 rc::Ref引用 rc::Weak 指向的节点>?
问题描述
我正在编写一个链接列表,其中存在链接前一个节点的弱引用。
use std::cell::{Ref, RefCell, RefMut};
use std::rc::{Rc, Weak};
pub struct List<T> {
head: NextLink<T>,
tail: PrevLink<T>,
}
type NextLink<T> = Option<Rc<RefCell<Node<T>>>>;
type PrevLink<T> = Weak<RefCell<Node<T>>>;
struct Node<T> {
elem: T,
prev: PrevLink<T>,
next: NextLink<T>,
}
impl<T> Node<T> {
fn new(elem: T) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
elem,
prev: Weak::new(),
next: None,
}))
}
}
impl<T> List<T> {
pub fn new() -> Self {
Self {
head: None,
tail: Weak::new(),
}
}
// add to tail
pub fn push(&mut self, elem: T) {
let new_node = Node::new(elem);
match self.tail.upgrade().take() {
Some(old_tail) => {
new_node.borrow_mut().prev = Rc::downgrade(&old_tail);
old_tail.borrow_mut().next = Some(new_node);
}
None => {
self.tail = Rc::downgrade(&new_node);
self.head = Some(new_node);
}
}
}
pub fn pop(&mut self) -> Option<T> {
self.tail.upgrade().map(|old_tail| {
match old_tail.borrow_mut().prev.upgrade() {
Some(new_tail) => {
new_tail.borrow_mut().next = None;
self.tail = Rc::downgrade(&new_tail);
}
None => {
self.head.take();
self.tail = Weak::new();
}
};
Rc::try_unwrap(old_tail).ok().unwrap().into_inner().elem
})
}
// add to head
pub fn unshift(&mut self, elem: T) {
let new_node = Node::new(elem);
match self.head.take() {
Some(old_head) => {
old_head.borrow_mut().prev = Rc::downgrade(&new_node);
new_node.borrow_mut().next = Some(old_head);
}
None => {
self.tail = Rc::downgrade(&new_node);
self.head = Some(new_node);
}
}
}
pub fn shift(&mut self) -> Option<T> {
self.head.take().map(|old_head| {
match old_head.borrow_mut().next.take() {
Some(new_head) => {
new_head.borrow_mut().prev = Weak::new();
self.head = Some(new_head);
}
None => {
self.tail = Weak::new();
}
};
Rc::try_unwrap(old_head).ok().unwrap().into_inner().elem
})
}
pub fn peek_head(&self) -> Option<Ref<T>> {
self.head
.as_ref()
.map(|node| Ref::map(node.borrow(), |node| &node.elem))
}
pub fn peek_tail(&self) -> Option<Ref<T>> {
self.tail
.upgrade()
.map(|node| Ref::map(node.borrow(), |node| &node.elem))
}
pub fn peek_head_mut(&mut self) -> Option<RefMut<T>> {
self.head
.as_ref()
.map(|node| RefMut::map(node.borrow_mut(), |node| &mut node.elem))
}
pub fn peek_tail_mut(&mut self) -> Option<RefMut<T>> {
unimplemented!()
}
}
impl<T> Drop for List<T> {
fn drop(&mut self) {
while let Some(old_head) = self.head.take() {
self.head = old_head.borrow_mut().next.take();
}
}
}
有一个编译错误:
error[E0515]: cannot return value referencing function parameter `node`
--> src/lib.rs:106:25
|
106 | .map(|node| Ref::map(node.borrow(), |node| &node.elem))
| ^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | `node` is borrowed here
| returns a value referencing data owned by the current function
看来,当尾节点的弱引用升级为 时Rc
,thisRc
归该函数所有,最终会被消耗掉。
我该如何解决?
解决方案
你的问题
使用Weak::upgrade
和RefCell::borrow
:
fn example<T>(foo: Weak<RefCell<T>>) {
let strong: Rc<RefCell<T>> = foo.upgrade().unwrap();
let the_ref: Ref<T> = strong.borrow();
}
你的问题
self.head.as_ref()
返回一个Option<&Rc<_>>
. self.tail.upgrade()
返回一个Option<Rc<_>>
. 当您调用Option::map
时,内部值的所有权将转移到闭包,并且您会收到您发布的错误。您可以调用Option::as_ref
,但是该函数拥有的,因此您不能返回引用,因为一旦被销毁Option
,它将无效。Rc
你唯一能做的就是从函数中返回Rc
。
也可以看看:
推荐阅读
- c# - 查找数据表中是否存在记录
- javascript - 在'自定义Debug\Release模式'下构建一个Js\Ts包?
- python-3.x - 使用最频繁的值按组填充缺失值
- dart - dart removeWhere() - 数据去哪儿了?
- flutter - 找不到名称或 ID 与“emulator-5554”匹配的设备
- typescript - 如何管理多个monorepos
- nullreferenceexception - 我正在使用 Google 图书 API。当我找到“5amclub”时,它显示了这本书的结果,但在找到“Nelson mandela”或“Ramayana”时不显示结果
- ruby-on-rails - Rails 应用程序以点 id 与斜线结尾,如何获得斜线路线?
- django - Django中的链接查询
- python - 将时间序列数据框分成一个有多个变量,每个变量都有年份的名称