匿名函数中的Scala返回语句

匿名函数中的Scala返回语句,scala,return,closures,anonymous-function,Scala,Return,Closures,Anonymous Function,为什么匿名函数中的显式return语句(使用return关键字的语句)从封闭的命名函数返回,而不仅仅是从匿名函数本身返回 例如,以下程序导致类型错误: def foo: String = { ((x: Integer) => return x) "foo" } 我知道建议避免使用return关键字,但我感兴趣的是,为什么显式和隐式return语句在匿名函数中具有不同的语义 在下面的示例中,m完成执行后,返回语句“生存”,程序将导致运行时异常。如果匿名函数没有从封闭函数返回,则无法

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

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

def foo: String = {
  ((x: Integer) => return x)
  "foo"
}
我知道建议避免使用
return
关键字,但我感兴趣的是,为什么显式和隐式return语句在匿名函数中具有不同的语义

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

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

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

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


总之,您应该只在允许条件(早期)返回的方法中使用
return
有关方法与函数的讨论,请参见。

从形式上讲,返回定义为始终从最近的封闭命名方法返回

返回表达式returne必须出现在某些 包含命名方法或函数的。最内层的封闭结构名为 源程序f中的方法或函数必须具有显式 声明的结果类型,并且e的类型必须符合它。回归 表达式计算表达式e并将其值作为 f的结果。对任何语句或表达式的求值 后面的返回表达式被省略

所以它在lambda中没有不同的语义。问题在于,与普通方法不同,从lambda创建的闭包可以逃避对封闭方法的调用,并且如果此类闭包中存在返回,则可以获得异常

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

现在,至于“为什么”。一个次要的原因是美学:lambda是表达式,当一个表达式及其所有子表达式具有相同的含义时,无论嵌套结构如何,这都是很好的。Neal Gafter在

不过,它存在的主要原因是,它允许您轻松模拟命令式编程中常用的控制流形式,但仍然允许您将内容抽象为高阶函数。例如,Java的foreach构造(
for(x:xs){yada;}
)允许在循环内返回。Scala没有语言级别的foreach。相反,它将foreach放入库中(不计算“for expression”而不产生任何结果,因为它们只是对foreach进行去糖处理)。使用非本地返回意味着您可以使用Java foreach并直接转换为Scala foreach


顺便说一句,Ruby、Smalltalk和CommonLisp(在我的脑海中)也有类似的“非本地”返回

这个答案实际上并没有回答为什么会这样,也就是说,这个决定背后的语言设计推理。@jcz这将变得非常模糊和不直观。想想lambdas,例如,
xs.foreach{x=>if(x==y)return x}
等等。你有没有更严肃的例子来说明为什么需要语义上的差异?因为您所列出的内容可以很容易地用具有谓词参数的修改后的
foreach
进行模拟。
object Foo { 
  def bar(i: Int): Int = return i + i
}