gpt4 book ai didi

scala - 为什么 scalac 会生成额外的/包装闭包

转载 作者:行者123 更新时间:2023-12-01 10:45:03 27 4
gpt4 key购买 nike

首先。考虑以下代码

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

最佳答案

让我们看看字节码。

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

关于scala - 为什么 scalac 会生成额外的/包装闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9396889/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com