rust - 内部可变性与数据隐藏以固定可变借用的所指对象

标签 rust borrow-checker borrowing interior-mutability

如果我们运行 this然后我们正确地得到错误“无法分配给不可变字段a.x”。

如果我们删除两个 //注释,并注释掉这个错误的行,然后我们得到错误“无法分配给 & 引用中的数据”。这是有道理的,因为 &mut不提供内部可变性。我们可以重新借用&A自由地,所以这不能提供可变访问,ala &&mut&&

如果我们删除 //评论和 /* */注释,然后整个编译,允许违反我们的不变量 a.x 的坏行。绝不能指向任何其他东西。

pub struct A<'a> {
    pub x: &'a mut [u8; 3],
}

fn main() {
    let y = &mut [7u8; 3];
    let /*mut*/ a = A { x: &mut [0u8; 3] };
    a.x[0] = 3;
    a.x = y;  //// This must be prevented!
    {
        // let b = &/*mut*/ a;
        // b.x[1] = 2;
    }
    println!("{:?}", a.x);
}

应该如何维持 x 这一不变量?一定不能改变吗?我们可以将字段设为私有(private),同时提供公共(public)解引用方法,但为 A 编写构造函数除外。在 Not Acceptable 情况下。

我们可以通过创建 A 来避免令人讨厌的构造函数。包装器的私有(private)成员 struct AA(A)它本身托管公共(public)解除引用方法。现在AA需要一个简单的构造函数,但它不需要 A 的所有字段的参数,不会影响执行顺序等。如果我们需要为 A 实现一些特征,这会变得很痛苦。和AA尽管。

然而,另一种方法是通过使用 Cell<A> 来使用内部可变性。 ,使用 Cell::replace 访问它,稍后再放回去。这听起来很有问题,但表明存在更多解决方案。

有更清洁的方法吗?

最佳答案

而不是使用 Cell<A>您可以将数组放在 A 内包含Cell<u8> s:

use std::cell::Cell;

pub struct A<'a> {
    x: &'a [Cell<u8>; 3],
}

fn main() {
    // let y = &mut [7u8; 3];
    let a = A { x: &[Cell::new(0u8), Cell::new(0u8), Cell::new(0u8)] };
    a.x[0].set(3);
    // a.x = y;
    {
        let b = &a;
        b.x[1].set(2);
    }
    println!("{:?}", a.x);
}

这仍然会按照您想要的方式运行,具有相同的性能,但现在 a变量是不可变的,因此您无法更改 a.x 。您也不需要使数组引用可变。

您的示例的一个小缺点是您无法使用数组重复语法,因为 Cell<T>不实现Copy 。这似乎是一个遗漏,但有一些解释说明为什么会出现 here .

关于rust - 内部可变性与数据隐藏以固定可变借用的所指对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42358738/

相关文章:

rust - 防 rust 传递箱引用,无动

rust - 为什么 .parse() 将 "42"转换为 f64 但无法将 "42.0"转换为 i32?

rust - 更改结构中一个字段的简单方法?

rust - 为什么我可以遍历一个切片两次,而不是一个向量?

rust - 如何设置Cap'n Proto RPC消息遍历限制?

rust - as_mut().unwrap() : Cannot infer lifetime due to conflicting requirements

recursion - 使用可变引用对app_state进行递归更新更新

rust - 在 Rust 中修剪集合的输入行

rust - 合并两个向量时匹配时为 "use of moved value"

rust - 如何将生命周期设置为闭包中捕获的值?