如何在Rust中解释对可变类型的不可变引用?

因为

如果我的取消引用链中任何不可变的引用,则似乎无法更改任何内容一个样品:

fn main() {
    let mut x = 42;
    let y: &mut i32 = &mut x; // first layer
    let z: &&mut i32 = &y; // second layer
    **z = 100; // Attempt to change `x`, gives compiler error.

    println!("Value is: {}", z);
}

我收到编译器错误:

error[E0594]: cannot assign to `**z` which is behind a `&` reference
 --> src/main.rs:5:5
  |
4 |     let z: &&mut i32 = &y; // second layer
  |                        -- help: consider changing this to be a mutable reference: `&mut y`
5 |     **z = 100; // Attempt to change `x`, gives compiler error.
  |     ^^^^^^^^^ `z` is a `&` reference, so the data it refers to cannot be written

从某种意义上讲,这是有道理的,因为否则编译器将无法防止对同一变量具有多个可变的访问路径。

但是,在查看类型时,语义似乎是违反直觉的:

  • 变量y具有类型&mut i32,或用简单的英语“对整数的可变引用”。
  • 变量的z类型为&&mut i32,或用简单的英语说成“对整数的可变引用的不变引用”。
  • 通过取消引用z一次(即*z),我将得到某种类型的&mut i32东西,即与相同类型的东西y但是,再次取消引用(即**z)会得到某种类型的东西i32,但不允许我对该整数进行突变。

从本质上讲,某种程度上的引用对我来说是谎言,因为它们实际上并没有按照自己的意愿去做。在这种情况下,我应该如何正确阅读引用类型,或者还应该如何恢复对该概念的信任?

使用此样本进行测试:

fn main() {
    let mut x = 42;
    let y: &mut i32 = &mut x; // first layer
    let m: &&mut i32 = &y; // second layer
    let z: &&&mut i32 = &m; // third layer
    compiler_builtin_deref_first_layer(*z);
}

fn compiler_builtin_deref_first_layer(v: &&mut i32) {
    compiler_builtin_deref_second_layer(*v);
}

fn compiler_builtin_deref_second_layer(w: &mut i32) {
    println!("Value is: {}", w);
}

最后两个函数的参数类型正确。如果我更改其中任何一个,编译器都会抱怨类型不匹配。但是,如果按原样编译示例,则会出现此错误:

error[E0596]: cannot borrow `**v` as mutable, as it is behind a `&` reference

以某种方式,对的调用compiler_builtin_deref_first_layer似乎还可以,但对的调用compiler_builtin_deref_second_layer却不是。编译器错误在谈论**v,但我只看到一个*v

布莱恩·坎贝尔

从本质上讲,某种程度上的引用对我来说是谎言,因为它们实际上并没有按照自己的意愿去做。在这种情况下,我应该如何正确阅读引用类型,或者还应该如何恢复对该概念的信任?

在Rust中读取引用的正确方法是作为权限。

如果不借用对象的所有权,则授予您对对象执行任何操作的权限。创建它,销毁它,将其从一个地方移到另一个地方。您是所有者,可以执行您想做的事情,可以控制该对象的寿命。

可变引用从所有者那里借用了对象。当可变引用处于活动状态时,它会授予对该对象的独占访问权限。没有人可以读取,写入或对该对象执行任何其他操作。可变引用也可以是调用和独占引用或独占借用。您必须将对象的控制权交还给原始所有者,但与此同时,您可以使用该对象进行任何操作。

不变的引用或共享借用意味着您可以与他人同时访问它。因此,您只能阅读它,而没有人可以对其进行修改,否则将根据操作发生的确切顺序产生不确定的结果。

可变的(或排他的)引用和不可变的(或共享的)引用都可以对拥有的对象进行,但这并不意味着您通过引用引用该对象时就拥有该对象。您可以通过哪种参考来约束对象的操作。

因此,不要将&&mut T引用视为“对T的可变引用的不可变引用”,然后再考虑“嗯,我不能改变外部引用,但我应该能够改变内部引用”。

取而代之的是,“某人拥有一个T。他们已经授予了独占访问权,所以现在有人有权修改该T。。但是与此同时,那个人已经授予了对该人的共享访问权&mut T,这意味着他们已经承诺不会在一段时间内对其进行更改,并且所有用户都可以使用的共享引用&mut T,包括取消引用基础,T但仅用于通常可以使用共享引用进行的操作,这意味着阅读但不能写作。”

最后要记住的是,可变或不可变部分实际上并不是引用之间的根本区别。实际上,这是排他性与共享性的一部分。在Rust中,您可以通过共享引用进行修改,只要有某种内部保护机制可以确保一次只有一个人这样做。有这样做的多种方式,例如CellRefCellMutex

因此&T&mut T提供的内容并不是真正的不变或可变的访问,尽管它们的名称如此命名,因为这是它们在没有任何库功能的情况下在语言级别提供的默认访问级别。但是,它们真正提供的是共享访问或互斥访问,然后,数据类型的方法可以根据调用者是采用私有值,专有引用还是共享引用来为调用者提供不同的功能。

因此,将引用视为权限;这是您可以参考的内容,它决定了您可以使用该内容做什么。而且,当您拥有所有权或排他性引用时,暂时提供排他性或共享引用会阻止您在那些借用引用仍然存在的情况下可变地访问对象。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章