Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 为什么将return作为函数中的最后一个语句被认为是糟糕的风格?_Rust - Fatal编程技术网

Rust 为什么将return作为函数中的最后一个语句被认为是糟糕的风格?

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

我在阅读Rust文档时发现了以下示例和语句

使用返回作为函数的最后一行是可行的,但被认为是拙劣的风格:

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