是否有替代方法或方法让 Rc> 限制 X 的可变性?

2024-05-01

:

use std::rc::Rc;
use std::cell::RefCell;

// Don't want to copy for performance reasons
struct LibraryData {
    // Fields ...
}

// Creates and mutates data field in methods
struct LibraryStruct {
    // Only LibraryStruct should have mutable access to this
    data: Rc<RefCell<LibraryData>>
}

impl LibraryStruct {
    pub fn data(&self) -> Rc<RefCell<LibraryData>> {
        self.data.clone()
    }
}

// Receives data field from LibraryStruct.data()
struct A {
    data: Rc<RefCell<LibraryData>>
}

impl A {
    pub fn do_something(&self) {
        // Do something with self.data immutably

        // I want to prevent this because it can break LibraryStruct
        // Only LibraryStruct should have mutable access 
        let data = self.data.borrow_mut();
        // Manipulate data
    }
}

我怎样才能预防LibraryData因在外部发生突变LibraryStruct? LibraryStruct应该是唯一能够变异的data在其方法中。这可能吗?Rc<RefCell<LibraryData>>或者还有其他选择吗?请注意,我正在编写“库”代码,以便我可以更改它。


如果您分享一个RefCell那么它总是有可能发生变异——这本质上就是它的全部意义。鉴于您能够更改的实施LibraryStruct,你可以确保data不是公开的,并通过 getter 方法控制它如何暴露给用户:

pub struct LibraryStruct {
    // note: not pub
    data: Rc<RefCell<LibraryData>>
}

impl LibraryStruct {
    // could also have returned `Ref<'a, LibraryData> but this hides your 
    // implementation better
    pub fn data<'a>(&'a self) -> impl Deref<Target = LibraryData> + 'a {
        self.data.borrow()
    }
}

在您的其他结构中,您可以通过将其视为参考来使事情变得简单:

pub struct A<'a> {
    data: &'a LibraryData,
}

impl<'a> A<'a> {
    pub fn do_something(&self) {
        // self.data is only available immutably here because it's just a reference
    }
}

fn main() { 
    let ld = LibraryData {};
    let ls = LibraryStruct { data: Rc::new(RefCell::new(ld)) };

    let a = A { data: &ls.data() };
}

如果您需要将参考保留更长时间,在此期间原始RefCell需要在库代码中可变地借用,那么您需要创建一个可以管理它的自定义包装器。可能有一个标准库类型,但我不知道它,并且很容易专门为您的用例制作一些东西:

// Wrapper to manage a RC<RefCell> and make it immutably borrowable
pub struct ReadOnly<T> {
    // not public
    inner: Rc<RefCell<T>>,
}

impl<T> ReadOnly<T> {
    pub fn borrow<'a>(&'a self) -> impl Deref<Target = T> + 'a {
        self.inner.borrow()
    }
}

现在在您的库代码中返回此内容:

impl LibraryStruct {
    pub fn data<'a>(&'a self) -> ReadOnly<LibraryData> {
        ReadOnly { inner: self.data.clone() }
    }
}

当你使用它的时候,内在RefCell将无法直接访问,并且数据只能不可更改地借用:

pub struct A {
    data: ReadOnly<LibraryData>,
}

impl A {
    pub fn do_something(&self) {
        //  data is immutable here
        let data = self.data.borrow();
    }
}

fn main() { 
    let ld = LibraryData {};
    let ls = LibraryStruct { data: Rc::new(RefCell::new(ld)) };

    let a = A { data: ls.data() };
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否有替代方法或方法让 Rc> 限制 X 的可变性? 的相关文章

随机推荐