95

我是一个新手 scala 程序员,遇到了一个奇怪的行为。

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true;
      else false;

    if (elem.head == '(')
      balanceMain(elem.tail, open, count + 1);....

以上基本上我想返回 true ifelem.isEmptycount == 0。否则,我想返回 false。

现在上面我已经读到不需要在 scala 中添加 return 语句。所以我在return上面省略了。但它不返回布尔值。如果我将 return 语句添加为return true. 它完美地工作。为什么会这样?

另外,为什么在 scala 中有 return 语句被认为是一种不好的做法

4

6 回答 6

152

这并不像省略return关键字那么简单。在 Scala 中,如果没有,return则将最后一个表达式作为返回值。因此,如果最后一个表达式是您想要返回的,那么您可以省略return关键字。但是如果你想要返回的不是最后一个表达式,那么 Scala就不会知道你想要返回它

一个例子:

def f() = {
  if (something)
    "A"
  else
    "B"
}

这里函数的最后一个表达式f是一个 if/else 表达式,它的结果是一个字符串。由于没有显式return标记,Scala 将推断您想要返回这个 if/else 表达式的结果:一个字符串。

现在,如果我们在 if/else 表达式之后添加一些内容:

def f() = {
  if (something)
    "A"
  else
    "B"

  if (somethingElse)
    1
  else
    2
}

现在最后一个表达式是一个计算结果为 Int 的 if/else 表达式。所以返回类型f将是 Int。如果我们真的希望它返回字符串,那么我们就有麻烦了,因为 Scala不知道这就是我们想要的。因此,我们必须通过将字符串存储到变量并在第二个 if/else 表达式之后返回它来修复它,或者通过更改顺序以使字符串部分最后发生。

return最后,即使使用像您这样的嵌套 if-else 表达式,我们也可以避免使用该关键字:

def f() = {
  if(somethingFirst) {
    if (something)      // Last expression of `if` returns a String
     "A"
    else
     "B"
  }
  else {
    if (somethingElse)
      1
    else
      2

    "C"                // Last expression of `else` returns a String
  }

}

于 2012-09-24T07:24:54.387 回答
25

如迄今为止的答案中所述,该主题实际上要复杂一些。Rob Norris 的这篇博文更详细地解释了它,并举例说明了何时使用 return 会实际破坏您的代码(或至少具有不明显的影响)。

在这一点上,让我引用这篇文章的精髓。最重要的陈述就在开头。将此打印为海报并将其贴在墙上 :-)

return关键字不是“可选的”或“推断的”;它改变了你程序的含义,你永远不应该使用它。

它给出了一个例子,当你内联一个函数时,它实际上破坏了一些东西

// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add

scala> sum(33, 42, 99)
res2: Int = 174 // alright

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR

scala> sumR(33, 42, 99)
res3: Int = 33 // um.

因为

表达式在return计算时会放弃当前计算并返回给return出现的方法的调用者。

这只是链接帖子中给出的示例之一,它是最容易理解的。还有更多,我强烈鼓励你去那里,阅读和理解。

当您来自 Java 等命令式语言时,起初这可能看起来很奇怪,但一旦您习惯了这种风格,它就会变得有意义。让我以另一句话结束:

如果您发现自己处于想要提前返回的情况,则需要重新考虑定义计算的方式。

于 2016-08-17T10:12:00.077 回答
5

默认情况下,将返回函数的最后一个表达式。在您的示例中,该点之后还有另一个表达式,您想要返回值。如果您想在最后一个表达式之前返回任何内容,您仍然必须使用return.

您可以像这样修改您的示例,以Boolean从第一部分返回 a

def balanceMain(elem: List[Char]): Boolean = {
  if (elem.isEmpty) {
    // == is a Boolean resulting function as well, so your can write it this way
    count == 0
  } else {
    // keep the rest in this block, the last value will be returned as well
    if (elem.head == "(") {
      balanceMain(elem.tail, open, count + 1)
    }
    // some more statements
    ...
    // just don't forget your Boolean in the end
    someBoolExpression
  }
}
于 2012-09-24T07:29:50.930 回答
5

我不会对 Scala 进行编程,但我使用另一种具有隐式返回的语言(Ruby)。你的代码if (elem.isEmpty)块后面有代码——最后一行代码是返回的,这就是为什么你没有得到你所期望的。

编辑:这也是编写函数的一种更简单的方法。只需使用 isEmpty 和 count 的布尔值自动返回 true 或 false:

def balanceMain(elem: List[Char]): Boolean =
{
    elem.isEmpty && count == 0
}
于 2012-09-24T07:22:35.593 回答
4

不要写if没有对应的语句else。一旦你添加else到你的片段中,你会看到你的trueandfalse实际上是函数的最后一个表达式。

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true
      else
        false
    else
      if (elem.head == '(')
        balanceMain(elem.tail, open, count + 1)
      else....
于 2012-09-24T18:35:26.587 回答
1

用于早期返回目的的用例匹配。它将强制您显式声明所有返回分支,防止忘记在某处写返回的粗心错误。

于 2019-03-01T20:52:10.970 回答