如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用? [英] How do I return a reference to something inside a RefCell without breaking encapsulation?

查看:22
本文介绍了如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a struct that has inner mutability.

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 立即超出范围.

The problem is that I can't have a function on Foo that returns a borrowed vec, because the borrowed vec is only valid for the lifetime of the Ref, but the Ref goes out of scope immediately.

我认为 Ref 必须坚持 因为:

I think the Ref must stick around because:

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

RefCell<T> uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCell<T>s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell<T> borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in task panic.

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

Now I could instead write a function like this that returns the entire interior:

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

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

However this potentially exposes fields (MutableInterior.hide_me in this example) that are really private implementation details to Foo.

理想情况下,我只想公开 vec 本身,可能带有一个守卫来实现动态借用行为.这样呼叫者就不必了解 hide_me.

Ideally I just want to expose the vec itself, potentially with a guard to implement the dynamic borrowing behavior. Then callers do not have to find out about hide_me.

推荐答案

您可以创建一个类似于 Ref<'a,T>RefCell::borrow 返回的守卫的新结构(),为了包装这个 Ref 并避免它超出范围,就像这样:

You can create a new struct similar to the Ref<'a,T> guard returned by RefCell::borrow(), in order to wrap this Ref and avoid having it going out of scope, like this:

use std::cell::Ref;

struct FooGuard<'a> {
    guard: Ref<'a, MutableInterior>,
}

然后,您可以为它实现 Deref trait,这样就可以像使用 &Vec 一样使用它:

then, you can implement the Deref trait for it, so that it can be used as if it was a &Vec<i32>:

use std::ops::Deref;

impl<'b> Deref for FooGuard<'b> {
    type Target = Vec<i32>;

    fn deref(&self) -> &Vec<i32> {
        &self.guard.vec
    }
}

之后,更新您的 get_items() 方法以返回一个 FooGuard 实例:

after that, update your get_items() method to return a FooGuard instance:

impl Foo {
    pub fn get_items(&self) -> FooGuard {
        FooGuard {
            guard: self.interior.borrow(),
        }
    }
}

Deref 有魔法:

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();
    let v: &Vec<i32> = &items;
}

这篇关于如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆