为什么Rust允许使用不可变绑定通过引用字段进行突变?
如果我有一个绑定到结构的不可变变量,Rust通常不允许我修改结构的字段,或者修改拥有的子结构的字段 但是,如果字段是可变引用,Rust将允许我对引用的对象进行变异,尽管我的绑定是不可变的 为什么允许这样做?这是否与Rust关于不变性的常规规则不一致 Rust不会让我通过不可变引用执行同样的操作,因此不可变引用与不可变绑定具有不同的行为 代码示例:为什么Rust允许使用不可变绑定通过引用字段进行突变?,rust,Rust,如果我有一个绑定到结构的不可变变量,Rust通常不允许我修改结构的字段,或者修改拥有的子结构的字段 但是,如果字段是可变引用,Rust将允许我对引用的对象进行变异,尽管我的绑定是不可变的 为什么允许这样做?这是否与Rust关于不变性的常规规则不一致 Rust不会让我通过不可变引用执行同样的操作,因此不可变引用与不可变绑定具有不同的行为 代码示例: struct Bar { val: i32, } struct Foo<'a> { val: i32, bar:
struct Bar {
val: i32,
}
struct Foo<'a> {
val: i32,
bar: Bar,
val_ref: &'a mut i32,
}
fn main() {
let mut x = 5;
{
let foo = Foo {
val: 6,
bar: Bar { val: 15 },
val_ref: &mut x
};
// This is illegal because binding is immutable
// foo.val = 7;
// Also illegal to mutate child structures
// foo.bar.val = 20;
// This is fine though... Why?
*foo.val_ref = 10;
let foo_ref = &foo;
// Also illegal to mutate through an immutable reference
//*foo_ref.val_ref = 10;
}
println!("{}", x);
}
结构栏{
瓦尔:i32,
}
struct Foo解释这一点的一个简单方法是,引用中的可变性和变量中的可变性是相互正交的。这两种形式的可变性是相关的,因为我们只能从一个可变变量(或绑定)中借用一些可变的东西。除此之外,每种二元组合都可能生锈:
参考可变性
-----------------------------
变量| x:&T | x:&mut T T|
易变性|------------+----------------|
|mut x:&T | mut x:&mut T|
-----------------------------
我们可以想到许多代码示例,举例说明使用这样一个变量x可以做什么。例如,可变引用的不可变变量可以修改另一个元素,但不能修改其本身:
let mut a = 5;
let mut b = 3;
let x: &mut i32 = &mut a;
*x = 10; // ok
x = &mut b; // nope! [E0384]
*x = 6;
即使作为结构中的字段,这也不会与Rust的安全保证相冲突。如果变量不可变地绑定到结构值,则每个字段也不可变。在本例中:
let mut x = 5;
let foo = Foo {
val: 6,
bar: Bar { val: 15 },
val_ref: &mut x
};
*foo.val_ref = 10;
此处未对foo
应用突变:foo.val\u ref
仍然指向x
。前者可以变异,因为它是可变借用的。
引用是独立进行借用检查的。编译器可以通过Foo
中的生存期参数'a
跟踪借用
第二个示例(如下所示)不起作用,因为从&Foo
,我们只能检索对其字段的引用(例如toval\u ref:&mut i32
)。反过来,为了防止别名,只能将&mut i32
强制为&i32
。不能通过不可变的引用可变地借用数据
let foo_ref = &foo;
*foo_ref.val_ref = 10; // error[E0389]
Rust不会让我通过一个不变的引用做同样的事情。因此,不可变引用与不可变绑定具有不同的行为
没错
另请参见:
,特别是:y是对可变引用的不可变绑定,这意味着您不能将y绑定到其他对象(y=&mut z),但可以对绑定到y的对象进行变异(*y=5)。细微的区别。
谢谢!我很好奇为什么我的最后一个例子,*foo\u ref.val\u ref=10代码>,是否无效?在这种情况下,我有一个对结构的不可变引用,我用它来读取对不同对象的可变引用。如果不可变绑定的另一种情况是这样的,为什么这不好呢?无论哪种方式,我都没有修改不可变结构的数据。(我想我的总体困惑是,它似乎不一致-似乎在某些情况下,可变性是可传递的,而在其他情况下,它似乎是不可传递的)@某种程度上说,可变性确实很聪明,通过引用继承:从&Foo
我们只能检索对其字段的不可变引用,而&mut T T
将成为&T
。明天我可以用这个问题更新答案。@E_net4所以我想知道为什么决定不通过绑定继承可变性。在我的例子中,我的感觉是Rust不应该接受任何一种。也就是说,如果我的绑定是不可变的,我就不能对引用进行传递性变异,即使我以可变方式借用了它们。另请参见:@Shepmaster确实那篇文章是类似的,尽管我的问题更多地集中在为什么*foo.val\u ref=10
是可接受的,而不是为什么另一个不能接受。从我的观点来看,我的示例中的任何东西都不应该通过不可变绑定被接受。