如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用? [英] How do I return a reference to something inside a RefCell without breaking encapsulation?
问题描述
我有一个具有内部可变性的结构.
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 forRefCell<T>
s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. BecauseRefCell<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屋!