首先。请考虑以下代码
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)
foreach和exception之间还有额外的anonfun。一个值应该是fail
本身的值(类Function1 []的对象),但第二个来自哪里?
foreach
签名采用此功能:
def foreach[U](f: A => U): Unit
那么,第二个目的是什么?
其次,请考虑以下代码:
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)
还有两个额外的anonfuns ......他们真的需要吗? :-E
答案 0 :(得分:4)
让我们看一下字节码。
object ExtraClosure {
val fail = (x: Any) => { throw new RuntimeException }
List(1).foreach(fail)
}
我们在(单个)匿名函数中找到:
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
所以它毕竟不是一个额外的关闭。我们有一个方法重载了两个不同的返回值(这对于JVM来说是完全可以的,因为它将所有参数的类型视为函数签名的一部分)。函数是通用的,因此它必须返回对象,但是您编写的代码专门返回Nothing
,它还会创建一个返回您期望的类型的方法。
有各种各样的方法,但没有一个没有他们的缺点。这是JVM非常擅长的事情,但是,我不会太担心它。
编辑:当然,在第二个示例中,您使用了def
,anonfun
是在函数对象中包装def
的类。这当然是必需的,因为foreach
需要Function1
。你必须以某种方式生成Function1
。