scala Closure自由变量

时间:2015-05-16 22:48:39

标签: scala

val m1 = 99

val g = (_:Int) + m1

g(10)  // returns 109

val m1 = 88

g(10)  // returns 109
var n1 = 99

val h = (_:Int) + n1

h(10)  // returns 109

n1 = 88

h(10)  // returns  98

var n1 = 66

h(10)  // returns 98

有人可以向我解释一下这是如何运作的吗? 为什么闭包不跟踪"自由变量"?的变化?

以下行是用 Scala编程编写的,但我发现很难将其链接到上述场景:

  

Scala的闭包本身捕获变量,而不是变量引用的值。

4 个答案:

答案 0 :(得分:6)

这看起来像一个REPL会话。每次引入val m1var n1时, shadow 以前的同名变量定义。阴影适用于此后发送到REPL的新行。但是已编译的行仍然引用旧变量。

通过重命名变量可以很容易地解释上述行为,从而不会发生阴影:每次重新声明某些内容时都会引入新名称。这会产生:

val m1 = 99

val g = (_:Int) + m1

g(10)  // returns 109

val m2 = 88

g(10)  // returns 109

-

var n1 = 99

val h = (_:Int) + n1

h(10)  // returns 109

n1 = 88

h(10)  // returns  98

var n2 = 66

h(10)  // returns 98

在这两种情况下,gh的定义仍然分别指代m1 / n1。新valvar的定义无关紧要。

但是,赋值n1 = 88不会引入新变量。它会更改现有变量n1的值。在这种情况下,h会看到n1的更新值。

答案 1 :(得分:2)

我假设您正在尝试在REPL中进行此操作。当您执行val m1 =var n1 = 第二时间时,解释很简单 - 您只是在制定新定义(您可能会将其视为{{1} } / m1_2),与您先前定义的n1_2 / m1无关(以任何方式)。您的n1h将关闭此先前定义的值/变量,无论它们是否受到新影片的影响。

P.S。你不能在REPL之外做这个技巧(例如在类定义上)

答案 2 :(得分:1)

您在REPL中所做的与

类似
object Test extends App{
  val m1 = 99

  val g = (_: Int) + m1

  println(g(10))   // returns 109

  {
    val m1 = 88    // creates a new variable that shadows m1
    println(g(10)) // returns 109
  }
}

您有两个名为m1的变量。 g的定义仅使用第一个。

答案 3 :(得分:0)

那是因为您正在使用Repl,它将您的语句封装到单个对象中,然后在后续使用时导入它们。因此,您正在目睹的特殊行为。

见帖子https://stackoverflow.com/a/22773553/2509908