回到斯卡拉

问题描述 投票:67回答:6

我是一个新手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如果elem.isEmptycount == 0。否则,我想返回false。

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

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

scala return
6个回答
116
投票

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

一个例子:

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

函数f的最后一个表达式是if / else表达式,其求值为String。由于没有标记明确的return,Scala会推断您想要返回此if / else表达式的结果:String。

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

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

  if (somethingElse)
    1
  else
    2
}

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

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

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
  }

}


17
投票

到目前为止,这个主题实际上有点复杂。这个blogpost by 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这样的命令式语言时,这一开始可能看起来很奇怪,但是一旦你习惯了这种风格它就会有意义。让我结束另一个引用:

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


4
投票

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

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

def balanceMain(elem: List[Char]): Boolean =
{
    elem.isEmpty && count == 0
}

4
投票

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

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

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
  }
}

3
投票

如果没有相应的if,请不要写else语句。一旦你将else添加到你的片段,你就会发现你的truefalse实际上是函数的最后一个表达式。

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....

0
投票

用例匹配用于提前退货。它将强制您明确声明所有返回分支,防止忘记在某处写入返回的粗心错误。

© www.soinside.com 2019 - 2024. All rights reserved.