gpt4 book ai didi

scala - scala 中的闭包是如何实现的?

转载 作者:行者123 更新时间:2023-12-03 05:05:49 28 4
gpt4 key购买 nike

创建函数时,如何将函数范围之外的变量拉入函数中?我尝试反编译,但我无法理解它。看起来它使用了 putfield。 putfield 是否创建一个指向对象引用的指针?

最佳答案

答案是“视情况而定”。 scala 2.11 版本可能会对此进行一些重大更改。希望 2.11 能够内联简单的闭包。

但无论如何,让我们尝试给出当前 scala 版本的答案(下面的 javap 来自 scala 2.10.2)。下面是一个非常简单的闭包,它使用 val 和 var,以及生成的闭包类的 javap 输出。正如您所看到的,如果您捕获 var 或捕获 val,则存在主要区别

如果你捕获一个 val,它只会作为副本传递给闭包类(你可以这样做,因为它是一个 val)。

如果捕获 var,则必须在调用站点位置更改 var 本身的声明。 var 不再是位于堆栈上的本地 int,而是转换为 scala.runtime.IntRef 类型的对象。 。这基本上只是一个装箱整数,但具有可变的 int 字段。

(这有点类似于当您想要从匿名内部类内部更新字段时使用大小为 1 的最终数组的 java 方法)

这对性能有一些影响。当你在闭包中使用 var 时,你必须生成闭包对象以及 xxxRef 对象来包含 var。一件重要的事情是,如果您有这样的代码块:

var counter = 0
// some large loop that uses the counter

并在其他地方添加一个捕获计数器的闭包,循环的性能将显着降低。

所以底线是:捕获 val 通常没什么大不了的,但是捕获 var 时要非常小心

<小时/>
object ClosureTest extends App {
def test() {
val i = 3
var j = 0
val closure:() => Unit = () => {
j = i
}
closure()
}
test()
}

这是生成的闭包类的javap代码:

public final class ClosureTest$$anonfun$1 extends scala.runtime.AbstractFunction0$mcV$sp implements scala.Serializable {
public static final long serialVersionUID;

public final void apply();
Code:
0: aload_0
1: invokevirtual #24 // Method apply$mcV$sp:()V
4: return

public void apply$mcV$sp();
Code:
0: aload_0
1: getfield #28 // Field j$1:Lscala/runtime/IntRef;
4: aload_0
5: getfield #30 // Field i$1:I
8: putfield #35 // Field scala/runtime/IntRef.elem:I
11: return

public final java.lang.Object apply();
Code:
0: aload_0
1: invokevirtual #38 // Method apply:()V
4: getstatic #44 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
7: areturn

public ClosureTest$$anonfun$1(int, scala.runtime.IntRef);
Code:
0: aload_0
1: iload_1
2: putfield #30 // Field i$1:I
5: aload_0
6: aload_2
7: putfield #28 // Field j$1:Lscala/runtime/IntRef;
10: aload_0
11: invokespecial #48 // Method scala/runtime/AbstractFunction0$mcV$sp."<init>":()V
14: return
}

关于scala - scala 中的闭包是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19806445/

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