这可能是一个半生不熟的想法,但我可以复制一个表达式的环境吗?请考虑以下示例:
class foo[T](block: => T) {
var data = { () => block }
def run() = { data() }
}
var a = 5
var b = new foo({ a += 1; println(a) })
var c = new foo({ a += 1; println(a) })
b.run()
c.run()
b.run()
c.run()
我得到以下输出:
6
7
8
9
但我真正想要的是以下内容:
6
6
7
7
简而言之,一旦初始值得到解决,我希望foo
拥有块中变量的副本,而不是引用它们。可以这样做吗? scala.util.DynamicVariable似乎很有希望,但我很难理解如何在上面的例子中使用它。
答案 0 :(得分:6)
如果你想制作副本,那么为什么不复制呢?
var c = new foo({ var aa = a + 1; println(aa) })
如果你想获取一个引用变量的现有闭包,并将其转换为一个引用该变量副本的闭包,那么我担心这是不可能的。
在任何情况下,除极少数情况和非常受控制的方式外,不应使用可变变量。也就是说,不要耍弄他们的参考文献。
答案 1 :(得分:2)
我认为你的问题是你正在关闭a(从而在你的程序运行时改变它的值),而不是关闭从a初始化的另一个变量。你可能想尝试更像这样的东西:
class bar[T](block: (T) => T, a: T) {
var cur = a
def run() = { cur = block(cur); cur }
}
var a = 5
var b = new bar((r: Int) => { val q = r + 1; println(q); q }, a)
var c = new bar((r: Int) => { val q = r + 1; println(q); q }, a)
b.run()
c.run()
b.run()
c.run()
输出:
6
6
7
7
但请注意,与您的代码不同,这不会影响a
变量运行时的值。
答案 2 :(得分:0)
1)正如上午已经提到过,在使用闭包时,你应该更喜欢不可变的概念。
2)另一方面,这正是闭包的用途。它们不捕获变量的值,它们捕获变量本身!你的问题有点颠倒了。实际上,您正在捕获环境 - 变量的环境。如果您不需要相同的变量而不是将其复制为n.m.或者Ian McLaird分别建议。