每当使用 声明变量时let
,它都是一个全新的变量,与之前的任何内容分开。即使已经存在同名变量,当新变量在作用域内时,原始变量也会被隐藏。如果一个变量被遮蔽,它通常是不可访问的。
在新变量超出范围后旧变量仍在范围内的情况下,或者如果旧变量有Drop
实现,则可以访问旧变量的值。
我们可以在以下示例中看到这一点。
#[derive(Debug)]
struct DroppedU32(u32);
impl Drop for DroppedU32 {
fn drop(&mut self) {
eprintln!("Dropping u32: {}", self.0);
}
}
fn main() {
let x = 5;
dbg!(&x); // the original value
{
let x = 7;
dbg!(&x); // the new value
}
dbg!(&x); // the original value again
let y = DroppedU32(5);
dbg!(&y); // the original value
let y = DroppedU32(7);
dbg!(&y); // the new value
// down here, when the variables are dropped in
// reverse order of declaration,
// the original value is accessed again in the `Drop` impl.
}
(操场)
这并不是说原始变量保证仍然存在。编译器优化可能会导致原始变量被覆盖,尤其是在原始变量不再被访问的情况下。
编码
pub fn add_three(x: u32, y: u32, z: u32) -> u32 {
let x = x + y;
let x = x + z;
x
}
编译为
example::add_three:
lea eax, [rdi + rsi]
add eax, edx
ret
如果你像我一样对汇编代码不太熟悉,这基本上
- 将 x 和 y 相加并将结果放入变量中(称为 w)。
- 将 z 添加到 w 并用结果覆盖 w。
- 返回 w。
所以(除了输入参数),即使我们使用let x = ...
了两次,也只使用了一个变量。中间结果let x = x + y;
被覆盖。