【发布时间】:2013-06-12 14:57:42
【问题描述】:
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 堆栈帧上的内存地址。我刚刚阅读了“Scala 编程”的闭幕章节,关于这个问题只有以下内容要说(第 155 页):
在这种情况下,Scala 编译器会重新排列事物,以便捕获的参数在堆中而不是堆栈中存在,因此可以比创建它的方法调用更有效。这个重排都是自动处理的,所以你不用担心。
谁能详细说明这在字节码级别是如何工作的?访问是否类似于具有所有相关同步和性能影响的类的成员变量?
【问题讨论】:
-
这被称为“funarg 问题”,我猜 wiki 可能有一些关于理论背景的指针:en.wikipedia.org/wiki/Funarg_problem。一般的解决方案似乎是“将激活记录或其中的一部分放在堆上”。 (谷歌也可以找到一些关于这个的演讲幻灯片/笔记或论文。)
-
注意 SIP 21 “孢子”(什么名字!)docs.scala-lang.org/sips/pending/spores.html
标签: scala memory-management closures