为什么使用return作为函数中的最后一个语句被认为是错误的样式?

Abh*_*jit 18 rust

我正在阅读Rust文档,并遇到了以下示例和声明

使用return作为函数的最后一行有效,但被认为是糟糕的样式:

fn foo(x: i32) -> i32 {
    if x < 5 { return x; }

    return x + 1;
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以写上面的内容

fn foo(x: i32) -> i32 {
    if x < 5 { return x; }

    x + 1
}
Run Code Online (Sandbox Code Playgroud)

但我更倾向于写前者,因为这更直观.我确实理解函数返回值应该用作表达式,以便后面有效但是为什么不鼓励前者呢?

Chr*_*gan 20

就是.

公约不需要特别好的理由,它们只需要是普遍接受的惯例.事实上,这个确实有一个相对较好的理由 - 因为你没有return和它一样短;.您可能认为这return x + 1;更直观,但我强烈反对 - 它真的很棒,我觉得有必要修复它.我说这是一个在开始使用Rust之前从未使用过面向表达式语言的人.在编写Python的时候,return x + 1在那个地方看起来是对的,在编写Rust时看起来不对.

现在,碰巧应该编写代码:

fn foo(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
}
Run Code Online (Sandbox Code Playgroud)

这强调了语言的表达方向.

  • "它就是." 对成年人来说不是一个好的答案.用户眼中的约定和风格.如果大多数用户发现使用返回直观,那么这是一种很好的风格,无论语言设计者的意见如何.[评论太久了,请阅读以下链接中的其余部分] https://gist.github.com/hzhou/432581d0735c035993a1d4bb1863d367 (18认同)
  • 正如文档所说,或者,我同意你的版本也是我真实写的方式。拉取请求时间... (3认同)
  • @Tshepang:什么,`匹配x {true => ...,false => ...}`?我在那里肯定不同意你的观点. (3认同)
  • 实际上,我更喜欢在这些职位上回归。_因为_ Rust 是面向表达式的,跟踪哪些块退出的次数足以使整个函数返回变得有点困难,并且当您需要提前返回时,在中间看到一两个 `return` stmt 变得很尴尬。 .. 面向表达式已经有很多其他的风格优势,但这感觉就像一个 _dis_advantage ,相反......(至少对于更长的函数) (2认同)

mja*_*mja 16

reddit复制:为什么 return 语句的语法不明确?


来自@pcwalton 的回答

显式返回在闭包中真的很烦人。例如,在引入 ES6 箭头函数之前,这是 JavaScript 的一大痛点

myArray.map(function(x) { return x * 2; })
Run Code Online (Sandbox Code Playgroud)

即使没有function关键字,它也非常冗长。一旦你在你的语言中的某个地方有隐式返回,为了一致性起见,你最好在任何地方都有它们。它使代码不那么冗长这一事实只是一个额外的好处。

来自@mozilla_kmc

Rust 是一种面向表达式的语言。一个块的形式

{
    stmt;
    stmt;
    ...
    stmt;
    expr
}
Run Code Online (Sandbox Code Playgroud)

这些语句(基本上)是表达式或let绑定,()如果未指定,则尾随表达式是隐式的。整个块的值就是最后一个表达式的值。

这不仅适用于函数。你可以写

let foo = if x { y } else { z };
Run Code Online (Sandbox Code Playgroud)

soif也取代了 C 的?:运算符。每种块都以相同的方式工作:

let result = unsafe {
    let y = mem::transmute(x);
    y.frob()
};
Run Code Online (Sandbox Code Playgroud)

所以函数末尾的隐式返回是 Rust 面向表达式语法的自然结果。改进的人体工程学只是一个很好的奖励:)

谜题:return x本身就是一种表达——它的价值是什么?

答案(由@dubiousjim 建议):

它是一个 never 类型!


Mar*_*ein 8

Clippy lint 给出了以下needless_returnlint 的原理:

去掉回车和分号会让代码更加生疏。

这可能是我们所能得到的最好的客观理由。

就直觉而言;我觉得它是由我们的个人经历决定的,因此是主观的。虽然 Rust 本身并不是一种函数式编程语言,但许多使用和开发它的人似乎对 Haskell 等完全基于表达式的函数式编程语言有很强的背景。在 Rust 的许多领域(例如错误处理)都可以强烈感受到这种影响。因此,对于他们(说实话,包括我自己)来说,使用表达式而不是声明似乎更优雅。


kke*_*eey 7

我强烈怀疑它源自函数式编程风格。(根据@Markus Klein 的回答)。

你的例子,在 OCaml 中:

let foo x = if x < 5 then x else x + 1
Run Code Online (Sandbox Code Playgroud)

与您在 Rust 中修改的示例进行比较:

fn foo(x: i32) -> i32 {
    if x < 5 { x } else { x + 1 }
}
Run Code Online (Sandbox Code Playgroud)

OCaml 中的闭包示例:

fun x -> if x < 5 then x else x + 1
Run Code Online (Sandbox Code Playgroud)

与 Rust 闭包相比:

|x| if x < 5 { x } else { x + 1 }
Run Code Online (Sandbox Code Playgroud)

所以Rust似乎采用了函数式编程风格。

为什么函数式编程语言要这样做?我不知道。 可能是因为return当代码中的含义已经很清楚时,到处乱扔 ' 会很烦人并且毫无意义。

函数式编程语言并不真正依赖于经典的“分配给变量,操作变量,返回变量”范例,而是使用“分配给变量,通过几个不同的函数管道变量,最终结果是输出”范例(并且甚至分配给变量也是可选的:搜索“无点编程”)。

Rust 中的“经典”范例示例:

fn qux(mut x: i32) -> i32 {
x = foo(x);
x = bar(x);
return x; // classic C style
}
Run Code Online (Sandbox Code Playgroud)

与 OCaml 中的函数式编程范例对比:

let qux x = x |> foo |> bar
Run Code Online (Sandbox Code Playgroud)

如果我们在 OCaml 示例中要求 a,return我们需要将其放在最开始,这在很大程度上是没有意义的,因为我们已经知道它将返回什么。

因此,出于上述原因,这种函数式编程风格可能会延续到 Rust。

例子:

Rust 的if语句计算结果为表达式,与 C(“经典”)和 OCaml(函数式)不同。