在编写必须返回值的函数时,有两种类似的方法:
#1(摘自rustbyexample)
// An integer division that doesn't `panic!`
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
// Failure is represented as the `None` variant
None
} else {
// Result is wrapped in a `Some` variant
Some(dividend / divisor)
}
}
#2(上述变体)
// An integer division that doesn't `panic!`
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
// Failure is represented as the `None` variant
return None
}
// Result is wrapped in a `Some` variant
Some(dividend / divisor)
}
我曾经写过第二段代码,但我在 The Rust Programming Language 或Rust By Example中的每个例子中都看到过它们使用的第一个案例。考虑到如上所述的匹配所有可能性代码,它只是造型还是存在性能差异?第一个是好的做法还是完全取决于我?
答案 0 :(得分:5)
在Rust playground上,您可以使用 ASM 和 LLVM IR 按钮查看某些代码如何编译为汇编程序(机器代码)或LLVM&# 39;中间表示。 LLVM IR通常更容易阅读,因为它比汇编程序更高级。
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
(注意:我正在执行I / O以获取编译器无法优化的值;常量过于激进且use std::io::BufRead;
// An integer division that doesn't `panic!`
#[inline(never)]
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
// Failure is represented as the `None` variant
None
} else {
// Result is wrapped in a `Some` variant
Some(dividend / divisor)
}
}
// An integer division that doesn't `panic!`
#[inline(never)]
fn checked_division2(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
// Failure is represented as the `None` variant
return None
}
// Result is wrapped in a `Some` variant
Some(dividend / divisor)
}
fn main() {
let stdin = std::io::stdin();
let i: i32 = stdin.lock().lines().next().unwrap().unwrap().parse().unwrap();
let j: i32 = stdin.lock().lines().next().unwrap().unwrap().parse().unwrap();
println!("{:?}", checked_division(i, j));
println!("{:?}", checked_division2(i, j));
}
函数完全消失,即使使用{{1} }。)
首先,让我们在发布模式下编译此代码。 LLVM IR是什么样的?这是checked_division
:
#[inline(never)]
这里checked_division
:
; Function Attrs: noinline uwtable
define internal fastcc i64 @_ZN16checked_division20h2cc10ba72e80f410faaE(i32, i32) unnamed_addr #0 {
entry-block:
switch i32 %1, label %next1 [
i32 0, label %join
i32 -1, label %cond2
]
next1: ; preds = %entry-block, %cond2
%2 = sdiv i32 %0, %1
%phitmp = zext i32 %2 to i64
%phitmp5 = shl nuw i64 %phitmp, 32
br label %join
cond2: ; preds = %entry-block
%3 = icmp eq i32 %0, -2147483648
br i1 %3, label %cond4, label %next1
cond4: ; preds = %cond2
tail call void @_ZN9panicking5panic20h77d028a733b1a80eiEKE({ %str_slice, %str_slice, i32 }* noalias nonnull readonly dereferenceable(40) @panic_loc3962)
unreachable
join: ; preds = %entry-block, %next1
%sret_slot.sroa.0.0 = phi i64 [ 1, %next1 ], [ 0, %entry-block ]
%sret_slot.sroa.3.0 = phi i64 [ %phitmp5, %next1 ], [ 0, %entry-block ]
%4 = or i64 %sret_slot.sroa.3.0, %sret_slot.sroa.0.0
ret i64 %4
}
如果你比较你最喜欢的差异工具中的两个功能(并排差异工具在这里更好,因为那里有一点噪音),你会注意到唯一的主要区别是checked_division2
在结尾处有一个名为; Function Attrs: noinline uwtable
define internal fastcc i64 @_ZN17checked_division220h9ae6c6af45a9a593DaaE(i32, i32) unnamed_addr #0 {
entry-block:
switch i32 %1, label %next1 [
i32 0, label %return
i32 -1, label %cond2
]
next1: ; preds = %entry-block, %cond2
%2 = sdiv i32 %0, %1
%phitmp = zext i32 %2 to i64
%phitmp5 = shl nuw i64 %phitmp, 32
br label %return
return: ; preds = %entry-block, %next1
%sret_slot.sroa.0.0 = phi i64 [ 1, %next1 ], [ 0, %entry-block ]
%sret_slot.sroa.3.0 = phi i64 [ %phitmp5, %next1 ], [ 0, %entry-block ]
%3 = or i64 %sret_slot.sroa.3.0, %sret_slot.sroa.0.0
ret i64 %3
cond2: ; preds = %entry-block
%4 = icmp eq i32 %0, -2147483648
br i1 %4, label %cond4, label %next1
cond4: ; preds = %cond2
tail call void @_ZN9panicking5panic20h77d028a733b1a80eiEKE({ %str_slice, %str_slice, i32 }* noalias nonnull readonly dereferenceable(40) @panic_loc3964)
unreachable
}
的块,而checked_division
在join
和checked_division2
之间有一个名为return
的块 - 但内容这些块都是一样的。换句话说,这些功能是完全等效的。
我们可以注意到的另一件事是,如果你尝试执行-2147483648 / -1,函数仍然会发生恐慌(-1测试是开头的next1
的一部分, -2147483648测试正好位于cond2
sdiv`指令下3将此情况记录为导致未定义的行为,因此Rust编译器通过恐慌来为您的函数提供明确定义的行为。
答案 1 :(得分:4)
这两个变体肯定会产生相同的代码。所以这只是风格问题。标准风格是使用第一种风格。