如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?

2024-03-22

我有一个具有内部可变性的结构。

use std::cell::RefCell;

struct MutableInterior {
    hide_me: i32,
    vec: Vec<i32>,
}
struct Foo {
    //although not used in this particular snippet,
    //the motivating problem uses interior mutability
    //via RefCell.
    interior: RefCell<MutableInterior>,
}

impl Foo {
    pub fn get_items(&self) -> &Vec<i32> {
        &self.interior.borrow().vec
    }
}

fn main() {
    let f = Foo {
        interior: RefCell::new(MutableInterior {
            vec: Vec::new(),
            hide_me: 2,
        }),
    };
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
}

产生错误:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:16:10
   |
16 |         &self.interior.borrow().vec
   |          ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 |     }
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 | /     pub fn get_items(&self) -> &Vec<i32> {
16 | |         &self.interior.borrow().vec
17 | |     }
   | |_____^

问题是我无法使用某个功能Foo返回借来的vec,因为借来的vec仅在该生命周期内有效Ref,但是Ref立即超出范围。

我觉得Ref必须坚持下去because http://doc.rust-lang.org/std/cell/struct.RefCell.html:

RefCell<T>使用 Rust 的生命周期来实现“动态借用”,这是一个可以声明对内部值的临时、独占、可变访问的过程。借用RefCell<T>与 Rust 的本机引用类型不同,它们是在“运行时”跟踪的,后者在编译时完全静态跟踪。因为RefCell<T>借用是动态的,可以尝试借用已经可变借用的值;当这种情况发生时,会导致任务恐慌。

现在我可以编写一个像这样的函数来返回整个内部:

pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;

然而,这可能会暴露字段(MutableInterior.hide_me在这个例子中),这些都是真正私有的实现细节Foo.

理想情况下我只是想暴露vec本身,可能有一个守卫来实现动态借用行为。那么调用者就不必了解hide_me.


您可以使用Ref::map https://doc.rust-lang.org/nightly/std/cell/struct.Ref.html#method.map(自 Rust 1.8 起)。这与以下结果相同莱文斯现有的答案 https://stackoverflow.com/a/29401865/155423:

use std::cell::Ref;

impl Foo {
    pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}

您还可以使用新功能,例如impl Trait隐藏Ref来自 API:

use std::cell::Ref;
use std::ops::Deref;

impl Foo {
    pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用? 的相关文章

随机推荐