我遇到了以下观察结果:
pub fn xx(mut x: Option<usize>) -> usize {
let y = x.take();
//print!("{:?}", x);
if let Some(x) = x {
x
} else {
0
}
}
此代码(print!
被注释掉)被优化为“无”:
xorl %eax, %eax
retq
一旦我取消注释 print!
,它就不能再优化 if let Some(x) = x
了。我继续扩展宏(使用 rustc +nightly --pretty=expanded -Z unstable-options main.rs
)并将代码最小化为最小的可编译示例:
#![feature(print_internals)]
#![feature(fmt_internals)]
pub fn xx(mut x: Option<usize>) -> usize {
let y = x.take();
std::io::_print(
::std::fmt::Arguments::new_v1_formatted(
&[""],
&[::std::fmt::ArgumentV1::new(&x, ::std::fmt::Debug::fmt)],
&[]
)
);
if let Some(x) = x {
x
} else {
0
}
}
据我所知,我们只引用了一次x
,而且它是一个不可变的引用,所以没有什么可以阻止优化器假设它是None
(因为我们 take()
它)并且只是不断地返回 0
就像在第一个片段中一样。
最佳答案
优化器只允许对程序进行不改变运行时行为的改变。通过打印选项
,您已经更改了运行时行为,因此优化器现在受到更多限制。
通过添加 print 语句,您可以使变量的地址可见并且对代码很重要:
&[::std::fmt::ArgumentV1::new(&x, ::std::fmt::Debug::fmt)],
// ^^
这意味着优化器不能再跳过为值生成内存位置或操作存储在其中的值。一旦你添加了所有关于动态调度和 IO 的垃圾,一个额外的 if
不会增加明显的开销。
您真正的答案是阅读 LLVM 源代码。优化非常重要,它们适用和不适用的深奥原因。
关于rust - 如果打印值,为什么 Rust 编译器不能优化 Option::take 和 "if let"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51120292/