Scala在匿名函数中返回语句

ama*_*emi 29 closures scala return anonymous-function

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

例如,以下程序导致类型错误:

def foo: String = {
  ((x: Integer) => return x)
  "foo"
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

def m: (Integer => Unit) =
  (x: Integer) => return (y: Integer) => 2
Run Code Online (Sandbox Code Playgroud)

Jam*_*Iry 20

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

返回表达式return e必须出现在一些封闭的命名方法或函数的主体内.源程序f中最内层的命名方法或函数必须具有显式声明的结果类型,并且e的类型必须符合它.返回表达式计算表达式e并返回其值作为f的结果.返回对返回表达式后面的任何语句或表达式的评估.

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

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

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

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

BTW,Ruby,Smalltalk和Common Lisp(在我的头脑中)也有类似的"非本地"回报.