将 RefMut 转换为 &mut

Rip*_*ide 3 rust

use std::cell::RefCell;
use std::rc::Weak;

struct Elem {
    attached_elem: Weak<RefCell<Elem>>,
    value: i32,
}

impl Elem {
    fn borrow_mut_attached_elem(&self) -> &mut Elem {
        //what should this line be?
        self.attached_elem.upgrade().unwrap().borrow_mut()
    }
}

fn main(){}
Run Code Online (Sandbox Code Playgroud)

我尝试过一些类似的其他线路,但到目前为止没有任何效果,甚至是 RefMut 的实验性 cell_leak 功能。

我不介意更改函数的签名,我只是想减少从 Elem 获取对 Attached_elem 的可变引用的开销。

use*_*342 7

这条线应该是什么?

您无法在该行中放置任何内容来(安全地)满足函数签名 - 这是有充分理由的。虽然RefCell确实允许&mut T从 a获取RefCell<T>(这就是它存在的原因),但它必须保证一次仅存在一个可变引用。它仅通过提供一个其生命周期与包装器相关的临时引用来实现这一点RefMut<T>。一旦包装器被删除,该值就会被标记为不再借用,因此引用的寿命不得超过它的寿命。

如果 Rust 允许你返回一个 bare &mut Elem,那么你就可以在RefCell不再被标记为借用后使用该引用。在这种情况下,什么可以阻止您再次调用borrow_mut_attached_elem()并获得对同一对象的第二个可变引用Elem

所以你肯定需要更改签名。如果您只需要向外部代码提供临时访问权限&mut Elem,最简单的方法是接受将接收它的闭包。例如:

fn with_attached_elem<R>(&self, f: impl FnOnce(&mut Elem) -> R) -> R {
    let rc = self.attached_elem.upgrade().unwrap();
    let retval = f(&mut *rc.borrow_mut());
    retval
}
Run Code Online (Sandbox Code Playgroud)

您可以调用它来对元素执行某些操作,例如:

elem.with_attached_elem(|e| e.value += 1);
Run Code Online (Sandbox Code Playgroud)

with_attached_elem注意返回闭包返回的值,允许您从调用者收集数据&mut Elem并将其传播给调用者。例如,要获取附加元素的值,您可以使用:

let value = elem.with_attached_elem(|e| e.value);
Run Code Online (Sandbox Code Playgroud)