Rust 为什么可以';我是否通过可变值的可变引用的不可变引用来更新值?
我发现以下几点很难理解:Rust 为什么可以';我是否通过可变值的可变引用的不可变引用来更新值?,rust,Rust,我发现以下几点很难理解: fn main() { let mut x: i32 = 10; { let y: &mut i32 = &mut x; *y += 10; println!("y={}", *y); let z: &&mut i32 = &y; // z += 10; // error[E0368]: binary assignment opera
fn main() {
let mut x: i32 = 10;
{
let y: &mut i32 = &mut x;
*y += 10;
println!("y={}", *y);
let z: &&mut i32 = &y;
// z += 10; // error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut i32`
// *z += 10; // binary assignment operation `+=` cannot be applied to type `&mut i32`
// **z += 10; //cannot assign to data in a `&` reference
}
println!("x={}", x);
}
当我包含*z+=10
时,错误消息为:
error[E0368]:二进制赋值操作`+=`不能应用于类型`&mut i32`
-->src/main.rs:10:9
|
10 |*z+=10;//二进制赋值操作“+=”不能应用于类型“%mut i32”`
| --^^^^^^
| |
|无法在类型“%mut i32”上使用“+=”`
|
=帮助:`+=`可以在'i32'上使用,您可以取消对`*z`:`**z的引用`
与y+=10完全相同代码>
既然*z
的类型为&mut i32
,与y
相同,为什么*y
可以用来更新x
的值,而**z
不能呢?您遗漏了一些mut
:
fn main() {
let mut x: i32 = 10;
{
let mut y: &mut i32 = &mut x;
*y += 10;
println!("y={}", *y);
let z: &mut &mut i32 = &mut y;
println!("z={}", z); // output: z=20
println!("*z={}", *z); // output: *z=20
println!("**z={}", **z); // output: **z=20
**z += 10;
}
println!("x={}", x);
}
- 您希望
y
是可变的->let mut y
- 您希望
&y
是可变的->..=&mut y
- 您希望将其分配给一个
&mut z
并将其引用为mutable=>让z:&mut&mut i32=…
我认为省略类型更直观:
fn main() {
let mut x = 10;
{
let mut y = &mut x;
*y += 10;
println!("y={}", *y);
let z = &mut y;
**z += 10;
}
println!("x={}", x);
}
mut
是unique
“可变”和“独特”之间的界限模糊,但在这种情况下,“可变”可能会导致错误的直觉<代码>&mut
引用实际上是唯一的引用:它们不能被别名。如果您有一个&mut T T
,您就知道当引用存在时,T
将不会通过任何其他引用进行访问(变异或只是读取)
(虽然您通常需要唯一的引用来变异值,但也有一些引用同时允许别名和变异。&Cell
就是其中之一:您不需要唯一访问单元格来变异其内容。&mut
引用始终是唯一的。)
编译器可以使用&mut
引用不能被别名的知识来执行优化。报告还有一些细节
&
引用是共享引用
另一方面,&
引用始终可以被其他&
引用使用别名。任何需要唯一访问T
的内容都必须保证不能使用其他引用访问T
。但是&&mut T T
不能保证这一点,因为它可能会被另一个&&mut T T
使用别名——对T
的独占访问不会被保留。但是您仍然可以使用&mut T
获取常规&T
,因为这不需要对&mut
的唯一访问
当然,这一切都是由Rust的类型系统强制执行的。考虑< <代码> Deref < /代码>和<代码> DerefMut < /> >定义:
获取&self
并返回&self::Target
。因此,您不需要唯一访问self
,就可以共享访问*self
使用&mut self
返回&mut self::Target
。因此,您确实需要唯一访问self
才能唯一访问*self
还有一件事阻止您通过简单地取消对&&mut T T
的引用而获得&mut T T
:
&mut
引用无法实现
我理解OP是在问为什么,而不是我需要做什么更改才能让代码正常工作。但我不希望y
本身是可变的。这里我希望y
借用的值是可变的。在此示例中,z
将能够更改y
的值,如*z=&mut i代码>,这不是我想要的。这在这里是不可能的。当查看我的第二个代码片段时,您可以看到原因:如果引用本身不可变,则不能将引用作为可变引用借用。在这种情况下,我们希望将z
放在一个块中。具体来说,我的意思是像这个。我仍然不明白为什么mut
是必要的,即使*z
的类型与y
相同。我认为错误的原因解释得很好,我不这么认为。如果以*z+=10运行它
并且它将提供帮助:+=可用于“i32”,您可以取消引用*z:*z
。误差与y+=10完全相同代码>,但*y+=10代码>将起作用,**z+=10代码>不起作用。&mut
引用确实是唯一的引用:它们不能有别名-挑剔:。虽然我们通常对这个术语很放松,但在这些细节的问题上,非常具体是值得的。答案中还有其他一些类似的问题。@Shepmaster我使用这个术语的方式与Nomicon相同:关于活跃度和重传有一些争论,但我不同意您的示例演示了&mut
引用的别名。谢谢您的回答。读了之后,不知何故我觉得&
只是语言的一个概念,如果我们有让y:&mut 32=&mut x实际上对于编译器来说,如果没有任何优化,我们就不会在堆栈中分配y
,对吗?@fishbone我不知道你的确切意思。如果您熟悉C,Rust的底层执行模型与C的基本相同,但是&
和&mut
引用是语言特性,允许编译器更容易地对难以或不可能用C表示的关系进行推理。这是否开始解决您的问题?@trentcl感谢您的解释。很清楚。