Scala 允许像这样的闭包
def newCounter = {
var a=0
() => {a+=1;a}
}
它定义了一个函数,每次调用时都会返回一个新的独立计数器函数,从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
像往常一样,这令人印象深刻a
将代表 newCounter 堆栈帧上的内存地址。我刚刚阅读了“Programming in Scala”的闭包章节,关于此事只有以下内容(第 155 页):
Scala 编译器在这种情况下会重新排列事物,以便捕获的参数存在于堆上,而不是堆栈上,因此可以比创建它的方法调用更长寿。这个重新安排都是自动完成的,所以你不必担心。
任何人都可以详细说明它在字节码级别上是如何工作的吗?访问是否类似于具有所有相关同步和性能影响的类的成员变量?
你可以使用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
}
}
}
任何一个都有一个包装var
由 lambda 使用。其他vars
(不在闭包中使用)是常见的语言环境变量。
该包装器的链接作为字段存储在函数实例中。
lambdalift
in -Xprint:lambdalift
is the 编译阶段 https://stackoverflow.com/a/4528092/406435。您可以获得所有阶段-Xshow-phases
。您可以使用阶段编号而不是名称,当您不确定需要哪个阶段时,它很有用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)