当一个值在Rust中隐藏另一个值时,在堆栈上会发生什么?

时间:2019-05-30 01:10:15

标签: rust borrow-checker borrow

我正在阅读Mastering Rust。在第一章的末尾有一个练习,其中提供了示例代码,其任务是修复该问题,并使用通常非常有用的编译器错误消息进行迭代。

期望以下内容是错误,但不是

for line in reader.lines() {
    let line = line.expect("Could not read line.");

对于完整的上下文,我有entire code in a gist。这是我修复问题后的代码,相关的行是37和38。但是,它需要将文本文件作为参数。


我期望发生错误,因为line在堆栈上(至少指针在堆栈上)。仍然可以毫无争议地销毁并更换它是对的吗?

关于内存管理和堆栈的幕后故事是什么?我假定line实际上是对字符串(&str类型)的引用。因此,这很好,因为在任何一种情况下,指针本身(堆栈上的对象)只是一个usize,因此两个line对象在堆栈上的大小相同。

我可以用其他尺寸的东西吗?第二行可以说:

let line: f64 = 3.42;

在这种情况下,对象本身在堆栈上,并且可能大于usize

1 个答案:

答案 0 :(得分:4)

无论何时使用Host声明变量,它都是一个全新的变量,与之前的任何变量分开。即使已经存在同名的变量,但新变量在范围内时,原始变量为shadowed。如果变量有阴影,则通常无法访问。

在新变量超出范围后,或者如果旧变量具有let实现的情况下,仍然可以访问旧变量的值,则可以访问旧变量的值。

我们可以在下面的示例中看到这一点。

Drop

(playground)

这并不是说原始变量肯定仍然存在。编译器优化可能会导致原始变量被覆盖,尤其是在不再访问原始变量的情况下。

代码

#[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.
}

compiles to

pub fn add_three(x: u32, y: u32, z: u32) -> u32 {
    let x = x + y;
    let x = x + z;
    x
}

如果您像我一样,对汇编代码不太熟悉,那么基本上

  1. 将x和y相加并将结果放入变量(称为w)。
  2. 将w添加z并用结果覆盖w。
  3. 返回w。

因此(除了输入参数之外),即使我们使用了两次example::add_three: lea eax, [rdi + rsi] add eax, edx ret ,也只使用了一个变量。中间结果let x = ...被覆盖。