[英]In Rust, what's the difference between "shadowing" and "mutability"?
在Rust Book 的第 3 章,变量和可变性中,我们对这个主题进行了几次迭代,以演示 Rust 中变量的默认、不可变行为:
fn main() {
let x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
哪些输出:
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
3 | println!("The value of x is {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
然而,由于 Rust 对阴影变量的看法,我们可以简单地这样做来改变仍然“不可变”的x
:
fn main() {
let x = 5;
println!("The value of x is {}", x);
let x = 6;
println!("The value of x is {}", x);
}
哪些输出(跳过细节):
The value of x is 5
The value of x is 6
有趣的是,这段代码也产生了上面的两行作为输出,尽管我们没有调用let
而是在第一次x
绑定到5
时调用了mut
:
fn main() {
let mut x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
这种在如何(并非真的)保护变量免于重新分配方面的模糊性似乎与保护绑定到不可变(Rust 默认)变量的值的既定目标背道而驰。 来自同一章(其中还包含阴影部分):
当我们尝试更改我们之前指定为不可变的值时,我们会遇到编译时错误,这一点很重要,因为这种情况会导致错误。 如果我们的代码的一部分基于值永远不会改变的假设而运行,而我们代码的另一部分更改了该值,则代码的第一部分可能不会执行其设计的目的。 这种错误的原因事后很难追查,尤其是当第二段代码只是偶尔更改值时。
在 Rust 中,编译器保证当你声明一个值不会改变时,它真的不会改变。 这意味着当您阅读和编写代码时,您不必跟踪值可能发生变化的方式和位置。 因此,您的代码更容易推理。
如果我可以通过一个足够无辜的调用let
我的不可变x
这个重要特性被mut
,为什么我需要mut
? 有什么方法可以真正地,认真地让x
不可变,这样就没有let x
可以重新分配其值?
我相信混淆是因为您将名称与存储混为一谈。
fn main() {
let x = 5; // x_0
println!("The value of x is {}", x);
let x = 6; // x_1
println!("The value of x is {}", x);
}
在此示例中,有一个名称 ( x
) 和两个存储位置( x_0
和x_1
)。 第二个let
只是重新绑定名称x
以引用存储位置x_1
。 x_0
存储位置完全不受影响。
fn main() {
let mut x = 5; // x_0
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
在此示例中,有一个名称 ( x
) 和一个存储位置 ( x_0
)。 x = 6
赋值直接改变了存储位置x_0
的位。
你可能会争辩说这些做同样的事情。 如果是这样,你就错了:
fn main() {
let x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
let x = 6; // x_1
println!("The value of y is {}", y);
}
这输出:
The value of y is 5
The value of y is 5
这是因为更改x
所指的存储位置对存储位置x_0
绝对没有影响,即y_0
包含指向的指针。 然而,
fn main() {
let mut x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
x = 6;
println!("The value of y is {}", y);
}
这将无法编译,因为您无法在借用x_0
时对其进行变异。
Rust 关心防止通过引用观察到的不需要的突变效应。 这与允许遮蔽并不冲突,因为您在遮蔽时不会更改值,您只是在以其他任何地方都无法观察到的方式更改特定名称的含义。 阴影是严格的局部变化。
所以是的,你绝对可以保持x
的值不被改变。 您不能做的是保持名称x
所指的内容不被更改。 最多,您可以使用像clippy
类的clippy
来拒绝将阴影视为 lint。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.