【问题标题】:Can I copy a closure in Scala?我可以在 Scala 中复制闭包吗?
【发布时间】:2011-10-04 03:30:54
【问题描述】:

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

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

【问题讨论】:

    标签: scala closures


    【解决方案1】:

    1) 作为 n.m.已经提到过,在使用闭包时你应该更喜欢不可变的概念。

    2) 另一方面,这正是闭包的用途。它们不捕获变量的,而是捕获变量本身!你的问题有点颠倒。你实际上是在捕捉环境——你的变量的环境。如果您不需要相同的变量,则将其复制为 n.m.或 Ian McLaird 分别建议。

    【讨论】:

      【解决方案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 变量在运行时的值。

      【讨论】:

        【解决方案3】:

        如果你想复制,那为什么不复制呢?

         var c = new foo({ var aa = a + 1; println(aa) })
        

        如果你想把一个引用变量的现有闭包变成一个引用该变量副本的闭包,那恐怕是不可能的。

        在任何情况下,不应该使用可变变量,除非在非常罕见的情况下并且以非常受控的方式。也就是说,不要玩弄他们的引用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多