Per*_*ids 16 closures memory-management scala
Scala允许关闭
def newCounter = {
var a=0
() => {a+=1;a}
}
Run Code Online (Sandbox Code Playgroud)
它定义了在每次调用返回一个新的独立的反函数开始一个函数1
:
scala> val counter1 = newCounter
counter1: () => Int = <function0>
scala> counter1()
res0: Int = 1
scala> counter1()
res1: Int = 2
scala> val counter2 = newCounter
counter2: () => Int = <function0>
scala> counter2()
res2: Int = 1
scala> counter1()
res3: Int = 3
Run Code Online (Sandbox Code Playgroud)
这是非常令人印象深刻的,因为通常a
会在newCounter的堆栈帧上代表内存地址.我刚刚阅读了"Scala编程"的封闭章节,并且在此事上只有以下内容(第155页):
Scala编译器在这种情况下重新排列事物,以便捕获的参数在堆上而不是堆栈中存在,因此可以比创建它的方法调用更长.这种重新安排都是自动完成的,因此您不必担心.
任何人都可以详细说明它如何在字节码级别上工作?访问是否类似于具有所有相关同步和性能影响的类的成员变量?
sen*_*nia 15
你可以scalac -Xprint:lambdalift <scala-file-name>
用来调查这个.
你的代码实际上是这样的:
def newCounter = {
val a: runtime.IntRef = new runtime.IntRef(0);
new Function0 {
private[this] val a$1 = a
def apply() = {
a$1.elem = a$1.elem + 1
a$1.elem
}
}
}
Run Code Online (Sandbox Code Playgroud)
var
lambda使用的是一个包装器.其他vars
(未在闭包中使用)是常见的区域设置变量.
此包装器的链接存储在函数实例中的字段中.
lambdalift
in -Xprint:lambdalift
是编译器阶段.你可以得到所有阶段-Xshow-phases
.您可以使用阶段编号而不是名称,当您不确定需要哪个阶段时,它很有用.