为什么Rust允许使用不可变绑定通过引用字段进行突变?

为什么Rust允许使用不可变绑定通过引用字段进行突变?,rust,Rust,如果我有一个绑定到结构的不可变变量,Rust通常不允许我修改结构的字段,或者修改拥有的子结构的字段 但是,如果字段是可变引用,Rust将允许我对引用的对象进行变异,尽管我的绑定是不可变的 为什么允许这样做?这是否与Rust关于不变性的常规规则不一致 Rust不会让我通过不可变引用执行同样的操作,因此不可变引用与不可变绑定具有不同的行为 代码示例: struct Bar { val: i32, } struct Foo<'a> { val: i32, bar:

如果我有一个绑定到结构的不可变变量,Rust通常不允许我修改结构的字段,或者修改拥有的子结构的字段

但是,如果字段是可变引用,Rust将允许我对引用的对象进行变异,尽管我的绑定是不可变的

为什么允许这样做?这是否与Rust关于不变性的常规规则不一致

Rust不会让我通过不可变引用执行同样的操作,因此不可变引用与不可变绑定具有不同的行为

代码示例:

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
,我们只能检索对其字段的引用(例如to
val\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
是可接受的,而不是为什么另一个不能接受。从我的观点来看,我的示例中的任何东西都不应该通过不可变绑定被接受。