我可以在Scala中复制一个闭包吗?

时间:2011-07-13 02:34:12

标签: scala closures

这可能是一个半生不熟的想法,但我可以复制一个表达式的环境吗?请考虑以下示例:

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似乎很有希望,但我很难理解如何在上面的例子中使用它。

3 个答案:

答案 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分别建议。