如何在 Rc<RefCell<_>> 中返回对 Vec 拥有的值的引用?

  • 本文关键字:拥有 Vec 引用 返回 RefCell Rc rust
  • 更新时间 :
  • 英文 :


假设以下代码

pub struct Universe {
components: Rc<RefCell<Vec<Component>>>,
active_component: Rc<RefCell<Option<usize>>>,
}

我想介绍一种方便的方法,它返回对活动组件的可变引用,例如

fn get_active_component(&mut self) -> Option<&mut Component> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
return self.components.borrow_mut().get_mut(i);
}
Option::None
}

导致错误

145 |             return self.components.borrow_mut().get_mut(i);
|                    ----------------------------^^^^^^^^^^^
|                    |
|                    returns a reference to data owned by the current function
|                    temporary value created here

我确实理解这个错误。borrow_mut((创建一个临时变量,该变量在函数返回后超出范围。但是,除了总是内联代码之外,我完全不知道如何在rust中实现这样的方法。

标准的方法是模拟RefCell的作用——返回一个代理结构,该结构将RefMut.borrow_mut()包装起来,并包含向量索引,实现DerefDerefMut

pub struct ComponentHandle<'a> {
vecref: RefMut<'a, Vec<Component>>,
index: usize,
}
impl Deref for ComponentHandle<'_> {
type Target = Component;

fn deref(&self) -> &Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked(self.index) }
}
}
impl DerefMut for ComponentHandle<'_> {
fn deref_mut(&mut self) -> &mut Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked_mut(self.index) }
}
}
impl Universe {
fn get_active_component(&mut self) -> Option<ComponentHandle<'_>> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let vecref = self.components.borrow_mut();
let index = *active_component_idx;

if index < vecref.len() {
return Some(ComponentHandle { vecref, index });
}
}

None
}
}

或者,此函数可以接受要调用的闭包,并将裸引用传递给它。这对代码来说更简单,但不太习惯:

fn get_active_component<F>(&mut self, f: F)
where F: FnOnce(Option<&mut Component>)
{
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
f(self.components.borrow_mut().get_mut(i));
} else {
f(None);
}
}

最新更新