scalac为何生成附加/包装闭包

scalac为何生成附加/包装闭包,scala,compiler-construction,closures,Scala,Compiler Construction,Closures,首先。考虑下面的代码 scala> val fail = (x: Any) => { throw new RuntimeException } fail: Any => Nothing = <function1> scala> List(1).foreach(fail) java.lang.RuntimeException at $anonfun$1.apply(<console>:7) at $anonfun$1.apply(&

首先。考虑下面的代码

scala> val fail = (x: Any) => { throw new RuntimeException }
fail: Any => Nothing = <function1>

scala> List(1).foreach(fail)
java.lang.RuntimeException
    at $anonfun$1.apply(<console>:7)
    at $anonfun$1.apply(<console>:7)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
那么,第二个的目的是什么

第二,考虑下面的代码:

scala> def outer() {
     |   def innerFail(x: Any) = { throw new RuntimeException("inner fail") }
     | 
     |   Set(1) foreach innerFail
     | }
outer: ()Unit

scala> outer()
java.lang.RuntimeException: inner fail
    at .innerFail$1(<console>:8)
    at $anonfun$outer$1.apply(<console>:10)
    at $anonfun$outer$1.apply(<console>:10)
    at scala.collection.immutable.Set$Set1.foreach(Set.scala:86)
scala>def outer(){
|def innerFail(x:Any)={抛出新的运行时异常(“内部故障”)}
| 
|设置(1)foreach innerFail
| }
外部:()单元
scala>outer()
java.lang.RuntimeException:内部失败
at.innerFail$1(:8)
在$anonfun$outer$1.应用(:10)
在$anonfun$outer$1.应用(:10)
位于scala.collection.immutable.Set$Set1.foreach(Set.scala:86)

还有两个额外的anonfuns。。。他们真的需要吗-让我们看看字节码

object ExtraClosure {
  val fail = (x: Any) => { throw new RuntimeException }
  List(1).foreach(fail)
}
我们发现,在(单个)匿名函数中:

def foreach[U](f: A => U): Unit 
public final scala.runtime.Nothing$ apply(java.lang.Object);
  Code:
   0:   new #15; //class java/lang/RuntimeException
   3:   dup
   4:   invokespecial   #19; //Method java/lang/RuntimeException."<init>":()V
   7:   athrow

public final java.lang.Object apply(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   invokevirtual   #27; //Method apply:(Ljava/lang/Object;)Lscala/runtime/Nothing$;
   5:   athrow
public final scala.runtime.Nothing$apply(java.lang.Object);
代码:
0:新#15//类java/lang/RuntimeException
3:dup
4:特别是#19//方法java/lang/RuntimeException。“”:()V
7:athrow
公共最终java.lang.Object应用(java.lang.Object);
代码:
0:aload_0
1:aload_1
2:invokevirtual#27//方法apply:(Ljava/lang/Object;)Lscala/runtime/Nothing$;
5:athrow
所以这毕竟不是一个额外的结束。我们有一个方法重载了两个不同的返回值(这对于JVM来说是完全正确的,因为它将所有参数的类型作为函数签名的一部分)。函数是泛型的,因此它必须接受对象返回,但是您编写的代码专门返回
Nothing
,它还创建了一个返回您期望的类型的方法

围绕这一点有各种各样的方法,但没有一种方法是没有缺点的。然而,JVM非常擅长避免这种情况,所以我不会太担心


编辑:当然,在第二个示例中,您使用了
def
,而
anonfun
是将该
def
包装到函数对象中的类。这当然是需要的,因为
foreach
需要
函数1
。您必须以某种方式生成
Function1

Scala版本2.9.2.rdev-2769-2011-12-13-g2dd83da(Java热点(TM)64位服务器虚拟机,Java 1.6.025)。哦。。。我懂了。但是使用(f:A=>Any)作为
foreach()
的参数不是更好吗?以避免这样的生成。@tuxSlayer-这仍然不行
A=>任何
都会被擦除到
Object=>Object
,该对象已被使用。