【问题标题】:How can I return a reference to the inner data of a RefCell<Option<T>>>? [duplicate]如何返回对 RefCell<Option<T>>> 内部数据的引用? [复制]
【发布时间】:2020-04-07 16:48:48
【问题描述】:

我正在创建一个延迟加载结构:

pub struct LazyData<T, U:FnOnce() -> T> {
    data:      RefCell<Option<T>>,
    generator: RefCell<Option<U>>,
}

impl<T,U:FnOnce() -> T> LazyData<T,U> {
    pub fn new(generator:U) -> LazyData<T,U> {
        LazyData {
            data:      RefCell::new(None),
            generator: RefCell::new(Some(generator)),
        }
    }
    ...
}

我已经尝试实现一个 get 方法来返回延迟加载的数据:

pub fn init(&self) {
    if self.data.borrow().is_none() {
        let generator = self.generator.replace(None).unwrap();
        let _none     = self.data.replace(Some(generator()));
    };
}

pub fn get(&self) -> &T {
    self.init();
    self.data.borrow().as_ref().unwrap()
}

但是编译器抱怨我返回的值引用了当前函数拥有的数据。这个错误对我来说很有意义,但我不确定如何解决它。

Here's a link to a full example.

【问题讨论】:

    标签: rust lazy-loading borrow-checker refcell


    【解决方案1】:

    找到了解决方法here!我可以使用Ref::map 来获取内部数据:

    pub fn get(&self) -> Ref<T> {
        self.init();
        Ref::map(self.data.borrow(), |borrow| {
            borrow.as_ref().unwrap()
        })
    }
    

    这个方法现在返回 Ref 而不是 &T,但我认为应该没问题。

    【讨论】:

    • 我会把这个问题留几天,以防有人有更好的解决方案/要添加的东西!
    • 您不能返回&amp;T,因为RefCell 上的borrow() 创建了一个临时的。一旦Ref 被销毁,它就让我们离开RefCell-borrow。想一想:通过返回Ref&lt;T&gt;,您实际上是在写锁定RefCell,直到Refget() 的调用者删除。这似乎是糟糕的隔离。为什么RefCell 会出现在首位?
    • 感谢您的回复!我将data 包裹在RefCell 中,这样get 方法就不需要&amp;mut self。如果没有RefCellinit 将需要&amp;mut self 才能将data 字段从None 更改为Some(...),因此与LazyData 的每个基本交互都需要可变性。
    • 我建议重新考虑这一点。您不希望对init() 进行可变访问这一事实导致get() 泄漏事实检查器,即当前通过Ref 可变借用的事实检查器get() 的调用者。这是在抢彼得付钱给保罗。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 2020-11-28
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多