Rust 为什么将return作为函数中的最后一个语句被认为是糟糕的风格?
我在阅读Rust文档时发现了以下示例和语句 使用返回作为函数的最后一行是可行的,但被认为是拙劣的风格:Rust 为什么将return作为函数中的最后一个语句被认为是糟糕的风格?,rust,Rust,我在阅读Rust文档时发现了以下示例和语句 使用返回作为函数的最后一行是可行的,但被认为是拙劣的风格: fn foo(x: i32) -> i32 { if x < 5 { return x; } return x + 1; } fn-foo(x:i32)->i32{ 如果xi32{ 如果xi32{ 如果x
fn foo(x: i32) -> i32 {
if x < 5 { return x; }
return x + 1;
}
fn-foo(x:i32)->i32{
如果x<5{返回x;}
返回x+1;
}
我知道我本可以把上面的内容写成
fn foo(x: i32) -> i32 {
if x < 5 { return x; }
x + 1
}
fn-foo(x:i32)->i32{
如果x<5{返回x;}
x+1
}
但我更倾向于写前者,因为前者更直观。我知道函数返回值应该作为一个表达式使用,这样后面的表达式就可以工作了,但是为什么不鼓励使用前者呢 就是这样
约定不需要有特别好的理由,它们只需要是普遍接受的约定。碰巧的是,这一个确实有一个比较好的理由,它比较短,因为您没有返回值
和代码>。您可能认为返回x+1
更直观,但我强烈反对它,因为它真的会让人恼火,我觉得迫切需要修复它。我这样说是因为在开始使用Rust之前,他从未使用过面向表达式的语言。在编写Python时,return x+1
在该位置看起来是正确的,而在编写Rust时,它看起来是错误的
现在碰巧的是,代码应该这样写:
fn foo(x: i32) -> i32 {
if x < 5 {
x
} else {
x + 1
}
}
fn-foo(x:i32)->i32{
如果x<5{
x
}否则{
x+1
}
}
这强调了语言的表达方向。摘自reddit:
答复
显式返回在闭包中真的很烦人。
例如
在引入ES6 arrow函数之前,这是JavaScript的一大难题
myArray.map(function(x) { return x * 2; })
即使没有函数
关键字,也是毫无意义的冗长。
一旦你的语言中有了隐含的回报,
为了保持一致性,你还不如把它们放在任何地方。
它减少了代码的冗长,这只是一个额外的好处
来自
Rust是一种面向表达式的语言。
一个区块具有以下形式:
{
stmt;
stmt;
...
stmt;
expr
}
这些语句(基本上)是表达式或let
绑定,
如果未指定,则尾部表达式将隐式地()
。
整个块的值就是最后一个表达式的值
这不仅仅是为了功能。你可以写
let foo = if x { y } else { z };
所以如果也代替了C的?:
操作符。
每种砌块的工作方式都相同:
let result = unsafe {
let y = mem::transmute(x);
y.frob()
};
因此,函数末尾的隐式返回是一个自然结果
Rust面向表达式的语法。
改进的人体工程学只是一个不错的奖励:)
谜题:returnX
本身就是一个表达式——它的值是什么
回答(由@dubiousjim建议):
这是一个从不使用的类型代码>
clippy lint给出了无需返回lint的以下合理性:
删除回车和分号会使代码更加生疏
这可能是一个客观的理由,因为我们将永远得到
就直觉而言;我觉得这是由我们的个人经历决定的,因此是主观的。虽然Rust本身不是一种函数式编程语言,但许多使用和开发它的人似乎对Haskell等完全基于表达式的函数式编程语言有着深厚的背景。在许多生锈区域(例如错误处理)都能强烈感受到这种影响。因此,对他们来说(老实说,包括我自己在内),使用表达式而不是语句似乎更优雅。我强烈怀疑它源自函数式编程风格。(根据@Markus Klein的回答)
您的示例(在OCaml中):
let foo x = if x < 5 then x else x + 1
fun x -> if x < 5 then x else x + 1
let qux x = x |> foo |> bar
与OCaml中的函数式编程范例相比:
let foo x = if x < 5 then x else x + 1
fun x -> if x < 5 then x else x + 1
let qux x = x |> foo |> bar
如果我们在OCaml示例中要求返回一个
,我们需要将它放在最开始的地方,这在很大程度上是没有意义的,因为我们已经知道它将返回什么
因此,出于上述原因,这种函数式编程风格很可能会延续到Rust。
例如:
Rust的if
语句计算为表达式,与C(“经典”)和OCaml(函数)不同。与流行的OOP语言不同,Rust是EOP,其中EOP=面向表达式的编程
当以结尾时代码>,这是一个表达式,因此块是一个表达式
相反,当结束时没有代码>,这是一条语句
我们编写了一个简单的函数来添加一个
fn add_one(x: i32) {
x + 1;
}
fn main() {
println!("{:#?}", add_one(1));
}
./target/debug/mytest
()
让我们删除代码>,
fn add_one(x: i32) {
x + 1
}
fn main() {
println!("{:#?}", add_one(1));
}
./target/debug/mytest //can't do this
这无法编译,因为函数将类型tuple与i32不匹配
我们修改函数
fn add_one(x: i32) -> i32 {
x + 1
}
fn main() {
println!("{:#?}", add_one(1));
}
./target/debug/mytest
2
有人说这是隐性回报,但我把->当作回报
此外,我们可以通过添加return将type强制输入到i32
现在我们做一个选择
fn add_one(x: i32, y: i32, s: i32) -> i32 {
if s == 1 {
x + 1
} else if s == 2 {
y + 1
} else {
0
}
}
fn main() {
println!("{:#?}", add_one(1, 2, 1));// choose x, not y
}
就不良风格而言,这主要是在这些条件流中,尤其是当它变得越来越大时
另一种情况是三元分配
更重要的是,在布尔
总之,我们最好不要使用return,而是像文档中所说的那样澄清函数的类型,或者,我也同意你的版本是我真正写这篇文章的方式。拉请求时间…每当有其他
,我宁愿看到使用匹配
;更好。@Tshepang:what,匹配x{true=>…,false=>…}
?我绝对不同意你的观点。事实上,我更喜欢回到那些位置。因为生锈是面向表达式的,所以跟踪哪个块退出整个函数返回的次数变得更加困难,当你需要早点返回时,看到<<代码>返回<代码> STMT或者中间两个就变得很尴尬了。表达导向已经有了很多其他的风格优势,但这让人感觉像是一种不优势
fn add_one(x: i32, y: i32, s: i32) -> i32 {
if s == 1 {
x + 1
} else if s == 2 {
y + 1
} else {
0
}
}
fn main() {
println!("{:#?}", add_one(1, 2, 1));// choose x, not y
}
fn add_one(x: i32, y: i32, s: i32) -> i32 {
if s == 1 { x + 1 } else { y + 1 }
}
fn main() {
println!("{:#?}", add_one(1, 2, 1));
}
fn assign_value(s: bool) -> i32 {
if s { 5 } else { -5 }
}
fn main() {
println!("{:#?}", assign_value(false));
}
./target/debug/mytest
-5