返回斯卡拉


80

我是新手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);....

基本上以上,如果elem.isEmpty和,我想返回true count == 0。否则,我想返回false。

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

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


2
目前通常不需要return关键字,只要你破坏你的代码成足够小的方法。
mauhiz 2012年

@mauhiz谢谢。你能解释一下吗?你会怎么做。
贾廷

4
看起来您正在参加Coursera Scala课程。最好的:)
weima 2012年

Answers:


137

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

一个例子:

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

在此,函数的最后一个表达式f是if / else表达式,其结果为字符串。由于没有显式return标记,Scala会推断您要返回此if / else表达式的结果:String。

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

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

  if (somethingElse)
    1
  else
    2
}

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

最后,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
  }

}


3
众神,谢谢!我一直在同一个问题上奋斗了几个小时(也在Coursera上了这门课程),却无法理解为什么需要退货。
伊戈尔·罗德里格斯

对于第一个示例,如果添加退货会发生什么。即return "A"return "B"
SamAko

@ T.Rex,它将返回值为“ A”或“ B”的f()的调用方。但是正如我在回答中解释的那样。切勿在Scala中使用return。Scala中的if语句以功能性方式工作。他们对某种类型的东西求值。就像Java(?:)中的三元运算符一样。示例:val foo = if(mybool)“ A” else“ B”-foo将是包含“ A”或“ B”的字符串。同样,考虑一个函数不返回任何东西,而是求值到其中最后一个表达式的值。
Grmpfhmbl '16

23

如到目前为止的答案所述,这个主题实际上稍微复杂一些。罗伯·诺里斯(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之类的命令性语言时,乍一看似乎很奇怪,但是一旦习惯了这种风格,它就会变得有意义。让我结束另一句话:

如果您发现自己想早日返回,则需要重新考虑定义计算的方式。


10
我不同意Rob的return观点,IMO,您不能只在lambda表达式中使用,但这是该语言中糟糕的设计选择,甚至不应该编译代码(在python中,使用lambda没有return语句的关键字可以避免这种情况)。 ..在其他情况下,return如果您要返回值,则在使用中没有发现真正的问题(是的,退出方法执行是因为在所有语言中都使用return!)
daveoncode

2
您可以自由发表意见,但是很多人都同意,在Scala中使用return至少是不好的风格。我敢于找到使用return的官方Scala doc示例。在正式文档中甚至没有对AFAIK进行解释,仅在规范文档中进行了说明(第6.20章)。用马丁·奥德斯基本人(Scala编程)的话说:“方法的推荐样式实际上是避免具有显式的(尤其是多个)返回语句。相反,应将每个方法视为产生一个值并返回的值的表达式。” 本书的第一版可免费在线获得artima.com/pins1ed
Grmpfhmbl,

4

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

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

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

谢谢。但是我只想在elem.isEmpty && count == 0返回true时返回,否则继续执行该块。即使错误,上述内容也会返回。
贾汀

@Jatin:啊,没意识到。explicit在这种情况下,尽早返回很合适。
jmdeldin 2012年

@Frank:在OP的代码中也未定义。我认为这是一个方法调用。
jmdeldin 2012年

4

不要写if没有相应内容的语句elseelse将片段添加到片段后,您将看到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....

5
我应用了它,得到了3个嵌套的IF,看起来很难看。有什么图案可以使它看起来更好吗?
Capacytron,2015年

4

默认情况下,将返回函数的最后一个表达式。在您的示例中,在要返回值的位置之后还有另一个表达式。如果您想在最后一个表达式之前返回任何内容,则仍然必须使用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
  }
}

9
不是“声明”。“表情”
维克多·巴生

0

用例匹配用于早期返回目的。这将迫使您显式声明所有的return分支,从而避免了忘记将return写入某处的粗心错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.