如何在结构中使用 Rc<RefCell<T>> 的数据类型?

Par*_*olu 3 rust

我正在尝试实现一个链接列表以用于学习目的。std::cell::RefCell 和 stc::rc::{Rc, Weak} 主要用于将数据存储到列表实例中。现在我正在实现fn pop,它使用并返回列表中第一个位置的值,但我不知道如何使用 Rc 和 RefCell 包装的值。

这是我的代码:

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
pub struct DbNode<T> {
    data: T,
    next: Option<Rc<RefCell<DbNode<T>>>>,
    prev: Option<Weak<RefCell<DbNode<T>>>>,
}

#[derive(Debug)]
pub struct DbList<T> {
    first: Option<Rc<RefCell<DbNode<T>>>>,
    last: Option<Weak<RefCell<DbNode<T>>>>,
}

pub fn push_front(&mut self, data: T) {
    match self.first.take() {
        Some(e) => {
            let new_front = Rc::new(RefCell::new(DbNode {
                data,
                next: Some(e.clone()),
                prev: None,
            }));
            let mut me = e.borrow_mut();
            me.prev = Some(Rc::downgrade(&new_front));
            self.first = Some(new_front);
        },
        None => {
            let new_data = Rc::new(RefCell::new(DbNode {
                data,
                next: None,
                prev: None,
            }));
            self.last = Some(Rc::downgrade(&new_data));
            self.first = Some(new_data);
        },
    }
}

pub fn push_back(&mut self, data: T) {
    match self.last.take() {
        Some(l) => {
            let new_back = Rc::new(RefCell::new(DbNode {
                data,
                next: None,
                prev: Some(l.clone()),
            }));
            let st = Weak::upgrade(&l).unwrap();
            let mut ml = st.borrow_mut();
            self.last = Some(Rc::downgrade(&new_back));
            ml.next = Some(new_back);
        },
        None => {
            let new_data = Rc::new(RefCell::new(DbNode {
                data,
                next: None,
                prev: None,
            }));
            self.last = Some(Rc::downgrade(&new_data));                
            self.first = Some(new_data);
        },
    }
}

pub fn pop(&mut self) -> Option<T> {
    match self.first.take() {
        Some(f) => {
            // How can I??
            // let result = Some(f.into_inner().data);
            // result
        },
        None => None,
    }
}
Run Code Online (Sandbox Code Playgroud)

我想要实现的是返回位于struct DbList中“first”的 struct DbNode中的内部“data”值,并将None设置为要使用的数据所在的“first”(如果“next”为None),否则将“下一个”设置为“第一个”。起初,我尝试使用Rc::downcast来消耗内部值,但匹配块中“f”的类型是“RefCell”,而不是“Rc”,然后我尝试使用 RefCell::into_inner(),但是编译器说:

无法移出Rc 移动发生,因为 value 具有 type std::cell::RefCell<ds::dll::DbNode<T>>,该类型未实现该Copy特征

我完全明白这意味着什么,但我不知道我应该做什么。正确的做法是什么??

kmd*_*eko 6

你很接近。使用Rc::try_unwrap()

Rc如果仅有一个强引用,则返回内部值。否则,Err将返回与传入的内容相同的内容Rc。即使存在未解决的弱引用,这也会成功。

pub fn pop(&mut self) -> Option<T> {
    match self.first.take() {
        Some(f) => {
            match Rc::try_unwrap(f) {
                Ok(refcell) => {
                    // you can do refcell.into_inner here
                    Some(refcell.into_inner().data)
                },
                Err(_) => {
                    // another Rc still exists so you cannot take ownership of the value
                    None
                }
            }
        },
        None => None,
    }
}
Run Code Online (Sandbox Code Playgroud)