LP_*_*LP_ 10 immutability rust
在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
Run Code Online (Sandbox Code Playgroud)
就像Java一样,这将有助于在程序中保持良好的语义限制final
(以非常有限的方式)。
同样,我们可以想象这种struct
利用内部不变性对内部不变数据进行非所有权引用的情况...
Dan*_*ath 11
具有单个字段的不变性是不可能的。在古代版本的Rust中(这是在0.8之前考虑的),这是一个选项,但由于规则使很多人感到困惑,因此将其删除。您可能会问,这令人困惑吗?这样想:如果一个字段被声明为可变的,而struct被声明为可变的,并且使用的引用是一个不变的引用(&
),则该字段为_______
。
正如Lily Ballard指出的那样,最好的方法是,您可以将Shape
字段声明为私有字段,并使用进行getter方法impl A {...}
。
mod inner {
pub struct A {
s: i32, // can't be seen outside of module
pub bla: i32,
}
impl A {
pub fn new() -> Self {
Self { s: 0, bla: 42 }
}
pub fn get_s(&self) -> i32 {
self.s
}
}
}
Run Code Online (Sandbox Code Playgroud)
let mut a = inner::A::new();
a.s = 42; // illegal
println!("{}", a.s); // also illegal
println!("{}", a.get_s()); // could be made to serve as a read-only method
Run Code Online (Sandbox Code Playgroud)
mod inner {
pub struct A {
s: i32, // can't be seen outside of module
pub bla: i32,
}
impl A {
pub fn new() -> Self {
Self { s: 0, bla: 42 }
}
pub fn get_s(&self) -> i32 {
self.s
}
}
}
Run Code Online (Sandbox Code Playgroud)
有一种提议可能会完全放弃可变性和不变性的概念(您不能说一个结构永远不会改变)。有关更改,请参见Niko的说明。
您不能在字段上强制不变性。必要时该结构将如何改变其自身的值?
您可以做的是将字段设为私有,并公开getter方法以返回对该字段的引用(或复制/克隆值)。
您可以创建一个结构体并且只为它实现 Deref 特性。没有 DerefMut 特性,包含的值不可能发生变异。
https://doc.rust-lang.org/std/ops/trait.Deref.html
这样,编译器将使成员可用,就好像它没有包装在另一个结构中一样,不需要任何编写的 getter 方法调用。
use std::ops::Deref;
/// A container for values that can only be deref'd immutably.
struct Immutable<T> {
value: T,
}
impl<T> Immutable<T> {
pub fn new(value: T) -> Self {
Immutable { value }
}
}
impl<T> Deref for Immutable<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
Run Code Online (Sandbox Code Playgroud)
struct Foo {
bar: Immutable<Vec<u8>>,
baz: usize,
}
impl Foo {
pub fn new(vec: Vec<u8>) -> Self {
Foo {
bar: Immutable::new(vec),
baz: 1337,
}
}
pub fn mutate(&mut self) {
self.bar.push(0); // This will cause a compiler error
}
}
Run Code Online (Sandbox Code Playgroud)
|
| self.bar.push(0);
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `runnable::immutable::Immutable<std::vec::Vec<u8>>`
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5180 次 |
最近记录: |