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的闭包本身捕获变量,而不是变量引用的值。
答案 0 :(得分:6)
这看起来像一个REPL会话。每次引入val m1
或var 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
在这两种情况下,g
和h
的定义仍然分别指代m1
/ n1
。新val
和var
的定义无关紧要。
但是,赋值n1 = 88
不会引入新变量。它会更改现有变量n1
的值。在这种情况下,h
会看到n1
的更新值。
答案 1 :(得分:2)
我假设您正在尝试在REPL中进行此操作。当您执行val m1 =
或var n1 =
第二时间时,解释很简单 - 您只是在制定新定义(您可能会将其视为{{1} } / m1_2
),与您先前定义的n1_2
/ m1
无关(以任何方式)。您的n1
和h
将关闭此先前定义的值/变量,无论它们是否受到新影片的影响。
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,它将您的语句封装到单个对象中,然后在后续使用时导入它们。因此,您正在目睹的特殊行为。