我如何在Rust中强制一个结构体的字段总是不可变的?

4szc88ey  于 2022-11-24  发布在  其他
关注(0)|答案(6)|浏览(186)

在Rust中,你没有在struct中指定可变性,但是它是从变量绑定继承的。这很好,但是有没有可能强制一个字段 * 总是 * 不可变的,即使根是可变的?
类似于以下假设语法:

struct A {
    immut s: Shape, // immutable by design
    bla: Bla, // this field inheriting (im)mutability
}
let mut a = make_a();
a.s = x/*...*/; // illegal

这将有助于在程序中保持良好的语义限制,就像Java的final所做的那样(以非常有限的方式)。
同样,我们可以想象这种struct有一些对内部不可变数据的非所有者引用,利用这种不可变性...

gkn4icbw

gkn4icbw1#

一个字段的不变性是不可能的。这是一个古老的version of Rust(想想0.8之前)中的选项,但它被放弃了,因为规则让很多人感到困惑。你可能会问,它是如何困惑的?这样想吧:如果一个字段被声明为可变的并且struct被声明为可变的并且所使用的引用是不可变引用(&),则该字段是_______
Lily Ballard noted的最佳做法是,可以将Shape字段声明为private,并使用impl A {...}创建一个getter方法。
第一个
有一个命题可能会完全放弃可变性和不变性的概念(你不能说一个结构体永远不会改变)。

ryevplcw

ryevplcw2#

你可以创建一个结构体,并且只为它实现Deref特性。如果没有DerefMut特性,就不可能改变包含的值。
https://doc.rust-lang.org/std/ops/trait.Deref.html
这样,编译器将使成员可用,就像它没有 Package 在另一个结构体中一样,不需要任何编写的getter方法调用。
第一个

cetgtptt

cetgtptt3#

你不能强迫一个字段具有不变性。结构体在必要的时候如何改变它自己的值呢?
您可以做的是将字段设为private,并公开getter方法以返回对它的引用(或复制/克隆值)。

dgjrabp2

dgjrabp24#

一个解决方案可能是采用更通用的方法:

pub struct Immutable<T> {
    value : T ,
}

impl<T> Immutable<T> {

    pub fn new(value : T) -> Immutable<T> {
        Immutable { value : value }
    }

    pub fn get( &self) -> &T { &self.value }
}

现在可以在每种情况下对每种其他类型使用不可变结构。
在模块中添加这个变量可以避免改变Immutable对象的内容。仍然可以通过一个新的Object覆盖它来改变保存Immutable对象本身的变量,但是你应该通过Immutable::new语句注意到它,这样你就可以避免使用它。

h4cxqtbf

h4cxqtbf5#

在许多情况下,* 关联常数 * 可实现所需的行为:

struct Foo { blah: Blah }

impl Foo {
    const S: Shape = Shape { x: 1, y: 1 };
}

当然,常量不能在创建时设置,它们在编译时设置。如果需要动态性,可以像其他答案中解释的那样将字段设置为私有。

pqwbnv8z

pqwbnv8z6#

现在最简单的实现方法可能是使用多产开发者大卫Tolnay(serde和其他许多书的作者)的readonly crate。
这个crate提供了一个属性宏来公开结构字段,这些字段在同一个模块内是可读和可写的,但只能在模块外可读。

#[readonly::make]
pub struct S {
    // This field can be read (but not written) by super.
    #[readonly]
    pub(super) readable: i32,

    // This field can be neither read nor written by other modules.
    private: i32,
}

相关问题