Rust 当一个值与另一个值成反差时,堆栈上会发生什么情况?
我正在读书。在第一章末尾有一个练习,其中提供了示例代码,任务是修复它,通过使用通常非常有用的编译器错误消息进行迭代 我原以为以下是一个错误,但它不是: 读取器中的行的Rust 当一个值与另一个值成反差时,堆栈上会发生什么情况?,rust,borrow-checker,borrow,Rust,Borrow Checker,Borrow,我正在读书。在第一章末尾有一个练习,其中提供了示例代码,任务是修复它,通过使用通常非常有用的编译器错误消息进行迭代 我原以为以下是一个错误,但它不是: 读取器中的行的。行(){ let line=line.expect(“无法读取行”); 对于完整的上下文,我有。这是我修复后的代码,相关的行是37和38。但是它需要输入一个文本文件作为参数 我以为会发生错误,因为行在堆栈上(至少指针在堆栈上)。它仍然可以被销毁和替换,而不必抱怨,这对吗 关于内存管理和堆栈,后台会发生什么?我假定line实际上
。行(){
let line=line.expect(“无法读取行”);
对于完整的上下文,我有。这是我修复后的代码,相关的行是37和38。但是它需要输入一个文本文件作为参数
我以为会发生错误,因为
行在堆栈上(至少指针在堆栈上)。它仍然可以被销毁和替换,而不必抱怨,这对吗
关于内存管理和堆栈,后台会发生什么?我假定line
实际上是对字符串的引用(a&str
类型)因此,这很好,因为在任何一种情况下,指针本身(堆栈上的对象)只是一个usize
,因此这两个行
对象在堆栈上的大小相同
我可以用不同尺寸的吗?第二行可以说:
let行:f64=3.42;
在这种情况下,对象本身在堆栈上,并且它可能大于usize
每当使用let
声明变量时,它都是一个全新的变量,与之前的任何变量都是分开的。即使具有相同名称的变量已经存在,原始变量仍然存在,而新变量在作用域中。I如果一个变量被隐藏,它通常是不可访问的
在新变量超出范围后旧变量仍在范围内的情况下,或者旧变量具有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
}
如果你和我一样,对汇编代码不太熟悉,基本上
将x和y相加,并将结果放入一个变量(称为w)
将z添加到w并用结果覆盖w
返回w
So(除输入参数外),只使用了一个变量,尽管我们使用了两次let x=…
。中间结果let x=x+y;
被覆盖。谢谢你,@SCappella!这回答了我的大部分困惑,但现在我有了另一个。我理解逻辑上发生的事情,但不理解内存分配和Rust中发生的事情0-成本抽象。如果我是影子,但在相同的范围内,就像你的第一个例子(let x=5;
…let x=7
),因为它是同一个作用域,所以不再存在x=5
的作用域。所以,在这种情况下,让x:i32=5
发生了什么事?让x:u64=7
?我的问题是:我在堆栈上有一个32位的项,它现在是同一堆栈位置上的64位项,对吗?我怎么做呢?@MikeWilliamson他们不占用相同的位置堆栈位置。原始变量被设置为不可访问,但它在内存中仍然保持不变。我将添加一个示例来说明这一点。@MikeWilliamson考虑它的最佳方式是将内部x
视为一个完全不同的变量,具有不同的名称。想象一下编译器甚至在内部重命名它(或表现得好像有)。很明显,这两个函数并不共享相同的堆栈位置,它们的类型也不存在任何问题。太好了,谢谢@SCappella!顺便说一句,你如何获得字节码,或者它编译成什么?在Python中,我使用了dis
库。Rust中有类似的东西吗?如果有,这是如何管理的,因为Rust编译到特定的体系结构/操作系统(同一个程序会在不同的平台上创建不同的字节码吗?或者字节码只是一个中介,就像在JVM或Python中一样?)@MikeWilliamson如果您想使用Cargo获取程序集,请参阅。如果您对在线工具没有异议,请查看。还可以选择发出程序集和Rust使用的其他中间表示形式。对于您的其他问题,请尝试提出新问题,我相信您会得到一个很好的答案。@Stargateur我不认为这是完全重复的,因为我潜在的问题不是为什么这是好的,而是如何这是好的?如何在引擎盖下的堆栈中发生事情以使这成为可能?是否有两个不同的对象,一个是旧的行
,另一个是新的行
,即使旧的不再可访问?还是旧的uly覆盖(如果在同一范围内)?如果是,对于不同大小的类型,如何实现?
example::add_three:
lea eax, [rdi + rsi]
add eax, edx
ret