Scala在匿名函数中返回语句

时间:2013-07-19 20:30:59

标签: scala return closures anonymous-function

为什么匿名函数中的显式return语句(使用return关键字的语句)从封闭的命名函数返回,而不仅仅是来自匿名函数本身?

E.g。以下程序导致类型错误:

def foo: String = {
  ((x: Integer) => return x)
  "foo"
}

我知道建议避免使用return关键字,但我对为什么显式和隐式返回语句在匿名函数中具有不同的语义感兴趣。

在以下示例中,m执行完毕后返回语句“幸存”,程序导致运行时异常。如果匿名函数没有从封闭函数返回,则无法编译该代码。

def main(args: Array[String]) {
  m(3)
}

def m: (Integer => Unit) =
  (x: Integer) => return (y: Integer) => 2

2 个答案:

答案 0 :(得分:20)

正式地说,返回被定义为始终从最近的封闭命名方法返回

  

返回表达式返回e必须出现在某些体内   包含命名的方法或功能。最里面的封闭命名   源程序中的方法或函数f必须明确   声明结果类型,e的类型必须符合它。回报   expression计算表达式e并返回其值作为   f的结果评估任何陈述或表达   返回表达式后面省略。

因此它在lambda中没有不同的语义。皱纹是,与普通方法不同,从lambda创建的闭包可以转义对封闭方法的调用,如果在这样的闭包中有返回,则可以获得异常。

  

如果返回表达式本身是匿名函数的一部分,那么它   可能是f的封闭实例已经返回   在返回表达式执行之前。在那种情况下,抛出   将不会捕获scala.runtime.NonLocalReturnException   传播调用栈。

现在,至于“为什么”。一个较小的原因是审美:lambdas是表达式,当表达式及其所有子表达式具有相同的含义时,无论嵌套结构如何,它都是很好的。 Neal Gafter在http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html

谈到这个问题

它存在的主要原因是,它允许您轻松模拟命令式编程中常用的控制流形式,但仍允许您将事物抽象为更高阶的函数。作为一个玩具示例,Java的foreach构造(for (x : xs) { yada; })允许在循环内返回。 Scala没有语言级别的foreach。相反,它把foreach放在图书馆里(不计算“表达”而没有收益,因为他们只是厌恶到foreach)。拥有非本地返回意味着您可以使用Java foreach并直接转换为Scala foreach。

BTW,Ruby,Smalltalk和Common Lisp(在我的脑海中)也有类似的“非本地”回报。

答案 1 :(得分:3)

return关键字是为(类)方法保留的,不能在函数中使用。您可以轻松测试:

object Foo {
  val bar = (i: Int) => return i + i
}

这给出了

<console>:42: error: return outside method definition
       object Foo { val bar = (i: Int) => return i + i }
                                          ^

大多数情况下,您可以将方法和函数视为相同,因为函数的apply方法在语法上表现得像调用方法,所谓的eta-expansion允许将方法作为函数参数传递。 / p>

在这种情况下,它会有所不同。定义为方法时,它是合法的:

object Foo { 
  def bar(i: Int): Int = return i + i
}

总之,您应该只在允许条件(早期)返回的方法中使用return有关方法与功能的讨论,请参阅this post