如果在我的解引用链中有任何不可变的引用,那么我似乎无法修改任何内容。一个例子:
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
。
z
进行一次解引用(即*z
),我将得到一个类型为&mut i32
的东西。不,那将是一个可变的解引用,这不能在不可变引用上进行。你最多只能从那里获得一个&i32
。 - E net4Deref
和DerefMut
。每个 trait 的文档都会解释在哪种情况下使用它们。 - E net4<&&mut i32 as Deref>::Target
是&mut i32
。查看Deref
trait 的定义并不能真正帮助这里,因为相关步骤是内置于编译器中的,而不是标准库中的。 - Sven Marnachy
是指向整数的排它引用,而z
是指向一个指向整数的排它引用的共享引用。但是,您不能对z
进行解引用来获取类似于y
的排它访问整数,因为这违反了z
自身“共享性”的合同。 - trent