如何斯卡拉保持变量的值定义关闭时?(How does Scala maintains the val

2019-07-30 14:42发布

斯卡拉是否通过复制或引用保持变量的值?

例如,在Ruby中“关闭实际上将延长所有它需要的变量的寿命。它不会复制它们,但将保留对它们的引用和变量本身将没有资格进行垃圾回收(如果该语言有垃圾收集),而闭包是围绕”。 [SKORKIN]

Answer 1:

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的垃圾收集器将不会删除通过封闭引用,只要关闭仍在引用的对象。



Answer 2:

而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]) ...


文章来源: How does Scala maintains the values of variable when the closure was defined?