相关问题: Scala 闭包与 Java 内部类相比 -> final VS var
我想知道 Scala 何时将捕获到闭包中的变量放在堆而不是堆栈上。我正在阅读 Martin Odersky 的 Scala 书,但现在我没有找到这些信息。有人可以解释引擎盖后面是什么吗?
相关问题: Scala 闭包与 Java 内部类相比 -> final VS var
我想知道 Scala 何时将捕获到闭包中的变量放在堆而不是堆栈上。我正在阅读 Martin Odersky 的 Scala 书,但现在我没有找到这些信息。有人可以解释引擎盖后面是什么吗?
scala 中的匿名函数(实际上是任何函数)实际上是一个对象(的实例Function*
)。当它被实例化时,通过将 val 复制到函数对象的内部字段来完成对 val 的捕获。在函数体中(即在函数对象的apply
方法中),对捕获的 val 的访问是通过访问这些字段来完成的。
vars 的捕获是类似的,除了编译器必须添加一个间接级别:通过一些隐藏的可变持有者(只是一个具有指向 var 的当前值的可变字段的对象)访问 var 值,这就是被复制到函数对象中的持有者。当写入 var 时(通过本地代码或函数对象),写入的是持有者的字段。这种机制确保本地代码和函数的代码操作相同的数据,并且都可以看到彼此的修改。
所以答案是捕获的 vals 和捕获的 var 都始终存在于堆中(无论是直接作为函数对象的字段,还是作为某个包装对象的字段)
我不知道编译器的内部情况,但这是如何完成的。对于每个局部变量,编译器维护一个初始化为 false 的标志。每当使用变量时,编译器都会检查它是否在不包含变量声明的类或闭包中使用;如果是这样,则标志设置为真。在变量范围的末尾,如果标志仍然为假,则变量可以存在于堆栈中。否则它必须存在于堆上。