Scala中“return”语句的作用是什么?

31

除了更加“Java友好”外,Scala提供return语句的真正原因是什么?

4个回答

48
忽略嵌套函数,总是可以用等效的没有返回值的计算替换带有返回值的Scala计算。这个结果可以追溯到“结构化编程”的早期时期,巧妙地称为结构化程序定理
在嵌套函数中,情况会发生变化。Scala允许你在一系列嵌套函数中深藏一个"return"。当执行返回时,控制权跳出所有嵌套函数,进入最内层的包含方法,从中返回(假设该方法实际上仍在执行,否则将抛出异常)。这种堆栈展开可以通过异常来完成,但不能通过机械重组计算来完成(就像没有嵌套函数那样可能)。
你实际上想要从嵌套函数中返回的最常见原因是打破命令式的for-comprehension或资源控制块。(即使它看起来只是一个语句,命令式的for-comprehension的主体也会被转换为嵌套函数。)
for(i<- 1 to bezillion; j <- i to bezillion+6){
if(expensiveCalculation(i, j)){
   return otherExpensiveCalculation(i, j)
}

withExpensiveResource(urlForExpensiveResource){ resource =>
// do a bunch of stuff
if(done) return
//do a bunch of other stuff
if(reallyDoneThisTime) return
//final batch of stuff
}

我认为这是一个更加正式的回答。我对你提到的结果的证明很感兴趣。你能提供一些参考资料吗? - Jus12
为结构化程序定理添加了维基百科链接。 - Dave Griffith

27

这提供的是为了适应那些难以或繁琐地安排所有控制流路径汇聚到方法的词法结尾的情况。

尽管像Dave Griffith所说的可以消除对return的任何使用,但通常这样做比仅仅用明显的return来中断执行更加混乱难懂。

还要注意,return返回的是方法,而不是可能在方法中定义的函数(文字)。


我知道那就是答案,只是想不出任何例子。 - Jus12

6

以下是一个例子

这个方法有很多if-else语句来控制流程,因为没有返回(这就是我想到的,你可以用你的想象力来扩展它)。我从一个实际的例子中提取出来并修改成了一个虚拟代码(实际上比这个还要长):

没有返回值:

 def process(request: Request[RawBuffer]): Result = {
      if (condition1) {
        error()
      } else {
        val condition2 = doSomethingElse()
        if (!condition2) {
          error()
        } else {
          val reply = doAnotherThing()
          if (reply == null) {
            Logger.warn("Receipt is null. Send bad request")
            BadRequest("Coudln't receive receipt")
          } else {
            reply.hede = initializeHede()
            if (reply.hede.isGood) {
              success()
            } else {
              error()
            }
          }
        }
      }
  }

带返回值的函数:

  def process(request: Request[RawBuffer]): Result = {
      if (condition1) {
        return error()
      }

      val condition2 = doSomethingElse()
      if (!condition2) {
        return error()
      }

      val reply = doAnotherThing()

      if (reply == null) {
        Logger.warn("Receipt is null. Send bad request")
        return BadRequest("Coudln't receive receipt")
      }

      reply.hede = initializeHede()
      if (reply.hede.isGood)
        return success()

      return error()
  }

在我看来,第二个比第一个更易读,甚至更易管理。如果不使用返回语句,缩进的深度(使用格式良好的代码)会越来越深,而我不喜欢这种情况 :)

2
我认为经验丰富的Scala程序员(不包括我)可以更清晰地理解第一个代码片段。 - Jus12
确实,这有点“品味”,取决于开发者的观点。例如,我最喜欢扁平化的样式。 - yerlilbilgin

2

在编写命令式风格的代码时,我认为return是一个有用的东西,这通常意味着I/O代码。如果你正在编写纯函数式代码,你不需要(也不应该使用)return。但是对于函数式代码,你可能需要惰性来获得等效于可以使用return“提前退出”的命令式代码的性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接