Rust 如何在不破坏封装的情况下返回对RefCell中某些内容的引用?
我有一个内部可变的结构Rust 如何在不破坏封装的情况下返回对RefCell中某些内容的引用?,rust,encapsulation,contravariance,mutability,interior-mutability,Rust,Encapsulation,Contravariance,Mutability,Interior 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. i
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();
}
但是,这可能会向Foo
公开真正属于私有实现细节的字段(MutableInterior.hide\u me
)
理想情况下,我只想公开
vec
本身,可能需要一个保护来实现动态借用行为。然后调用方不必了解hide\u me
您可以创建一个类似于Ref的新结构。您可以创建一个类似于Ref的新结构,而不是创建一个全新的类型,您可以使用(因为Rust 1.8)。这与以下结果相同:
您可以使用(因为Rust 1.8),而不是创建一个全新的类型。这与以下结果相同:
您可以将Vec
包装在Rc
中
use std::cell::RefCell;
use std::rc::Rc;
struct MutableInterior {
hide_me: i32,
vec: Rc<Vec<i32>>,
}
struct Foo {
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn get_items(&self) -> Rc<Vec<i32>> {
self.interior.borrow().vec.clone() // clones the Rc, not the Vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Rc::new(Vec::new()),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
使用std::cell::RefCell;
使用std::rc::rc;
结构可变内部{
隐藏我:i32,
vec:Rc,
}
结构Foo{
内部:RefCell,
}
impl-Foo{
发布fn获取项目(&self)->Rc{
self.interior.borrow().vec.clone()//克隆Rc,而不是vec
}
}
fn main(){
设f=Foo{
内部:RefCell::新建(可变内部){
vec:Rc::new(vec::new()),
隐藏我:2,
}),
};
设f=&f;
let items=借用的项目。获取项目();
}
当需要对Vec
进行变异时,使用以获取对Vec
的可变引用。如果仍有其他Rc
s引用Vec
,make_mut
将Rc
与其他Rc
分离,克隆Vec
并更新自身以引用新的Vec
,然后为您提供一个可变引用。这确保了另一个Rc
s中的值不会突然改变(因为Rc
本身不提供内部可变性)。您可以将Vec
包装在Rc
中
use std::cell::RefCell;
use std::rc::Rc;
struct MutableInterior {
hide_me: i32,
vec: Rc<Vec<i32>>,
}
struct Foo {
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn get_items(&self) -> Rc<Vec<i32>> {
self.interior.borrow().vec.clone() // clones the Rc, not the Vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Rc::new(Vec::new()),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
使用std::cell::RefCell;
使用std::rc::rc;
结构可变内部{
隐藏我:i32,
vec:Rc,
}
结构Foo{
内部:RefCell,
}
impl-Foo{
发布fn获取项目(&self)->Rc{
self.interior.borrow().vec.clone()//克隆Rc,而不是vec
}
}
fn main(){
设f=Foo{
内部:RefCell::新建(可变内部){
vec:Rc::new(vec::new()),
隐藏我:2,
}),
};
设f=&f;
let items=借用的项目。获取项目();
}
当需要对Vec
进行变异时,使用以获取对Vec
的可变引用。如果仍有其他Rc
s引用Vec
,make_mut
将Rc
与其他Rc
分离,克隆Vec
并更新自身以引用新的Vec
,然后为您提供一个可变引用。这确保了另一个Rc
s中的值不会突然改变(因为Rc
本身不提供内部可变性)。这是唯一的/惯用的方法吗?看起来有点麻烦。。。虽然我假设不使用getItems()方法,您可以直接借用块中的内部构件,然后它将超出范围(或者在RefCell
的特定情况下是…@Norcalli),但当引用超出范围时需要通知对象(这是Ref
的析构函数所做的)。在这里,我们需要保留这种行为(OP的错误是由于Ref
实例被过早删除),并对其进行封装。这是唯一的/惯用的方法吗?看起来有点麻烦。。。虽然我假设不使用getItems()方法,您可以直接借用块中的内部构件,然后它将超出范围(或者在RefCell
的特定情况下是…@Norcalli),但当引用超出范围时需要通知对象(这是Ref
的析构函数所做的)。在这里,我们需要保留这种行为(OP的错误是由于Ref
实例被过早删除),并因此对其进行封装。如果您正在实现std::ops::Index trait,它要求您返回&Self::Output,那么如何代替get_项呢。据我所知,返回std::cell::Ref不能满足trait需求。“有没有一种方法可以使这种特性具有内部变异性呢?事实上,我找到了一种处理不完美的特性的方法,所以我想这可能就足够了。”丹尼尔夫。我不相信UnsafeCell
实现,因为它很可能会引入内存不安全性。如果实现std::ops::Index trait,需要返回&Self::Output,那么如何代替get\u项呢。据我所知,返回std::cell::Ref不能满足trait需求。“有没有一种方法可以使这种特性具有内部变异性呢?事实上,我找到了一种处理不完美的特性的方法,所以我想这可能就足够了。”丹尼尔夫。我不相信UnsafeCell
实现,因为它很可能会导致内存不安全。
use std::ops::Deref;
impl<'b> Deref for FooGuard<'b> {
type Target = Vec<i32>;
fn deref(&self) -> &Vec<i32> {
&self.guard.vec
}
}
impl Foo {
pub fn get_items(&self) -> FooGuard {
FooGuard {
guard: self.interior.borrow(),
}
}
}
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;
}
use std::cell::Ref;
impl Foo {
pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
Ref::map(self.interior.borrow(), |mi| &mi.vec)
}
}
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)
}
}
use std::cell::RefCell;
use std::rc::Rc;
struct MutableInterior {
hide_me: i32,
vec: Rc<Vec<i32>>,
}
struct Foo {
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn get_items(&self) -> Rc<Vec<i32>> {
self.interior.borrow().vec.clone() // clones the Rc, not the Vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Rc::new(Vec::new()),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}