斯卡拉是否通过复制或引用保持变量的值?
例如,在Ruby中“关闭实际上将延长所有它需要的变量的寿命。它不会复制它们,但将保留对它们的引用和变量本身将没有资格进行垃圾回收(如果该语言有垃圾收集),而闭包是围绕”。 [SKORKIN]
斯卡拉是否通过复制或引用保持变量的值?
例如,在Ruby中“关闭实际上将延长所有它需要的变量的寿命。它不会复制它们,但将保留对它们的引用和变量本身将没有资格进行垃圾回收(如果该语言有垃圾收集),而闭包是围绕”。 [SKORKIN]
Scala的闭包也不要深拷贝的对象,他们将只保留对对象的引用。 此外,封闭没有得到它自己的词汇范围,而是,它使用周围的词汇范围。
class Cell(var x: Int)
var c = new Cell(1)
val f1 = () => c.x /* Create a closure that uses c */
def foo(e: Cell) = () => e.x
/* foo is a closure generator with its own scope */
val f2 = foo(c) /* Create another closure that uses c */
val d = c /* Alias c as d */
c = new Cell(10) /* Let c point to a new object */
d.x = d.x + 1 /* Increase d.x (i.e., the former c.x) */
println(f1()) /* Prints 10 */
println(f2()) /* Prints 2 */
我不能在垃圾收集意见,但我认为JVM的垃圾收集器将不会删除通过封闭引用,只要关闭仍在引用的对象。
而JVM没有关闭,它只是反对。 Scala编译器生成实施用于在代码闭合的每次出现相应功能性状(取决于参数和结果类型的签名的)匿名类。
例如,如果由于某种l : List[Int]
则写l.map(i => i + 1)
它会被转换为
class SomeFreshName extends Function[Int, Int] {
def apply(i: Int) = i + 1
}
l.map(new SomeFreshName())
在这种情况下,不存在真正的封闭,如在I => I + 1,不存在自由变量,仅参数i和常数。
如果关闭了一些当地的丘壑,或等效的函数的参数,他们将不得不为构造函数的参数于封闭,实现类要传递:
对于l.map(i => s + i)
其中s是一个字符串参数或局部的方法的,它会做
class SomeFreshName(s: String) extends Function[Int, String] {
def apply(i: Int) = s + i
}
l.map(new SomeFreshName(s))
根据需要通过许多参数的构造函数。
注意:如果s是类而不是本地方法的字段,然后s + i
会其实this.s + i
,和this
将被传递给匿名类。
没有什么特别的垃圾收集器(再次,在JVM不知道封的),简单地说,当封闭对象有个基准,S至少会生活,只要关闭对象。
需要注意的是同样的事情发生在无名类的Java语言。 当一个匿名类使用封闭方法的当地居民,那些当地人默默地加入作为匿名类的字段,并且在构造函数。
在Java中,这是允许的只有在当地是final
,这相当于阶的val
,而不是var
。
事实上,这个实现,只要关闭被创建,它有自己的它关闭其他变量的副本。 如果修改它们,这些修改将不会反映在该法。 如果它们在闭合修改,这将不会反映在该方法中。
假设你写
var i = 0
l.foreach{a => println(i + ": " + a); i = i + 1}
println("There are " + i + " elements in the list")
之前描述的实施将
class SomeFreshName(var i: Int) extends Int => Unit {
def apply(a: Int) = println(i + ": " + a); i = i + 1
}
var i = 0
l.foreach(new SomeFreshName(i)
println("There are " + i + " elements in the list")
这样做,将有两个可变i
,一种在该方法中,和所述一个在SomeFreshName
。 只有一个在SomeFreshName将被修改,最后的println将始终报告0元素。
斯卡拉通过更换引用对象在封闭拍摄VAR解决他的问题。 给定一个类
class Ref[A](var content: A)
的代码首先被取代
val iRef = new Ref[Int](0)
l.foreach{a =>
println(iRef.content + ": " + a);
iRef.content += iRef.content + 1
}
println("There are " + i + " elements in the list")
这当然只是为VAR恰好是采取封闭,而不是每一个VAR完成。 这样做,所述变种已被替换为缬氨酸,实际变量值已被移动到堆中。 现在,闭合可以做到像往常一样,和它的工作原理
class SomeFreshName(iRef: Ref[Int]) ...