我对移动和复制的直觉一定是错的。我希望Rust编译器优化一个不可变值的移动作为一个no-op。因为这个值是不可变的,我们可以在移动后安全地重用它。但是Rust 1.65.0 on Godbolt编译到汇编,将这个值复制到内存中的一个新位置。我正在研究的Rust代码:
pub fn f_int() {
let x = 3;
let y = x;
println!("{}, {}", x, y);
}
生成的-C opt-level=3
部件:
; pub fn f_int() {
sub rsp, 88
; let x = 3;
mov dword ptr [rsp], 3
; let y = x;
mov dword ptr [rsp + 4], 3
mov rax, rsp
...
为什么let y = x;
会导致mov dword ptr [rsp + 4], 3
和mov rax, rsp
?为什么编译器不将y
视为程序集中x
的同一个变量?
(This question看起来很相似,但它是关于不是复制的字符串的。我的问题是关于复制的整数的。看起来我所描述的不是错过的优化机会,而是我理解上的根本错误。)
2条答案
按热度按时间nbysray51#
如果你像这样改变你的例子
进行优化
宏(以及
write!()
...)获取其参数上的引用,并使用这些引用提供格式化机制。(没有内联)需要数据存储在内存中的某个地方才能有地址。因为类型是Copy
,语义暗示我们具有两个不同的存储器,否则,共享存储器将是对 * 移动 * 操作(而不是 * 复制 *)的优化。qq24tv8q2#
我不认为这是你理解中的一个根本错误,但这里有一些有趣的观察。
首先,由于
println!()
的设计,它(尤其是格式化机制)很难优化,所以println!()
没有优化也就不足为奇了。第二个是it is generally not obvious it is OK to perform this optimization, because it observably make the addresses equivalent。
println!()
获取打印值的地址(并将其传递给一个opaque函数)。事实上,Copy
类型比非Copy
类型更难在这方面进行调整,因为对于Copy
类型,原始变量在移动后仍然可以使用,而对于非Copy
类型it is possible that not。