Can I copy a closure in Scala?
This is perhaps a half-baked idea, but can I copy the environment of an expression? Consider the following example:
class foo[T](block: => T) {
var data = {开发者_如何学JAVA () => 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()
I get the following output:
6
7
8
9
But what I really want is the following:
6
6
7
7
In short, I want foo
to have copies of the variables in the block instead of referring to them, once the initial value has been resolved. Can this be done? scala.util.DynamicVariable seems promising, but I'm having a hard time understanding how I might use it in the example above.
If you want to make a copy, then why not make a copy?
var c = new foo({ var aa = a + 1; println(aa) })
If you want to take an existing closure that refers to a variable, and turn it into a closure that refers to a copy of that variable, then I'm afraid it's not possible.
In any case, mutable variables should not be used except in very rare circumstances and in a very controlled manner. That is, not juggling their references.
I think your problem is that you're closing over a (and thus changing its value as your program runs), rather than closing over a different variable initialized from a. You might want to try something more like this:
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()
Output:
6
6
7
7
However, note that unlike your code, this will not affect the value of the a
variable as it runs.
1) As n.m. already mentioned, you should prefer immutable concepts when using closures.
2) On the other hand this is exactly what closures are for. They don't capture the value of the variabe, they capture the variable itself! Your question is kinda upside-down. You actually are capturing the environment - the environment of your variable. If you don't need the same variable than copy it as n.m. or Ian McLaird respectively suggested.
精彩评论