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();
}