在 Rust 中,当一个值影响另一个值时,堆栈上会发生什么? [英] What happens on the stack when one value shadows another in Rust?

查看:52
本文介绍了在 Rust 中,当一个值影响另一个值时,堆栈上会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am reading Mastering Rust. There is an exercise at the end of the first chapter where sample code is provided, and the task is to fix it, iterating by using the generally quite helpful compiler error messages.

预计以下是一个错误,但不是:

I was expecting that the following was an error but it is not:

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

对于完整的上下文,我有整个代码的要点.这是我修复后的代码,相关行是 37 &38. 但是它需要提供一个文本文件作为参数.

For complete context, I have the entire code in a gist. That's the code after I fixed things, and the relevant rows are 37 & 38. However it requires feeding a text file as an argument.

我期待一个错误,因为 line 在堆栈上(至少指针在).它仍然可以毫无怨言地摧毁和替换是对的吗?

I was expecting an error because line is on the stack (at least the pointer is). Is it right that it can still be destroyed and replaced with no complaint?

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

What happens under the hood regarding memory management and the stack? I presume that line is actually a reference to a string (a &str type). So, then, this is fine because in either case, the pointer itself - the object on the stack - is just a usize, so that both line objects are of the same size on the stack.

我可以用不同尺寸的东西来做这个吗?第二行可以说:

Can I do this with something of a different size? Could the second line have said:

let line: f64 = 3.42;

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

In this case, the object itself is on the stack, and it is potentially larger than usize.

推荐答案

每当使用 let 声明变量时,它都是一个全新的变量,与之前的任何变量都分开.即使已经存在同名变量,原始变量也是shadowed 而新变量在范围内.如果一个变量被隐藏,它通常是不可访问的.

Whenever a variable is declared with let, it's an entirely new variable, separate from anything before it. Even if a variable with the same name already exists, the original variable is shadowed while the new variable is in scope. If a variable is shadowed, it's normally inaccessible.

在新变量超出范围后旧变量仍在范围内的情况下,或者旧变量具有 Drop 实现的情况下,可以访问旧变量的值.

It's possible to access the value of the old variable in situations where the old variable is still in scope after the new variable falls out of scope, or if the old variable has a Drop implementation.

我们可以在下面的例子中看到这一点.

We can see this in action in the following example.

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

(游乐场)

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

That's not to say that the original variable is guaranteed to still exist. Compiler optimizations can cause the original variable to be overwritten, especially if the original variable isn't accessed again.

代码

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

如果你像我一样不太熟悉汇编代码,这基本上

If you're like me and aren't too familiar with assembler code, this basically

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

所以(除了输入参数),即使我们使用了两次 let x = ... ,也只使用了一个变量.中间结果 let x = x + y; 被覆盖.

So (besides the input parameters), there's only one variable used, even though we used let x = ... twice. The intermediate result let x = x + y; gets overwritten.

这篇关于在 Rust 中,当一个值影响另一个值时,堆栈上会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆