Reputation: 166
Here is the code I'm referring to:
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
Following is the output when it is run:
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90
I don't get how x
is being assigned in the return
statement in the adder
function? It does not seem to be passed anywhere in the function.
I also don't get how the sum
variable works. Shouldn't it get reset everytime the function adder
is called and be assigned the value 0
?
Upvotes: 0
Views: 922
Reputation: 488183
Go handles first-class functions and closures in a pretty typical / standard way. For some good background on closures in general, see the Wikipedia article. In this case, calling adder
itself:
int
object named sum
with value 0
.sum
.The particular function-like thingy that adder
returns, which its caller captures in an ordinary variable, is a function that takes one argument. You then call it, passing the one argument. There's nothing special about this argument-passing: it works the same way as it would anywhere else. Inside the function-like thingy, using the variable x
gets you the value that the caller passed. Using the name sum
gets you the captured int
object, whatever its value is. Returning from the function leaves the captured int
still captured, so a later call to the same function-like thingy sees the updated int
in sum
.
By calling adder
twice, you get two slightly-different function-like thingies: each one has its own private sum
. Both of these private sum
s are initially zero. Calling the function-like thingy whose value you've saved in pos
gets you the function that uses one of them. Calling the slightly-different function-like thingy whose value you've saved in neg
gets you the function that uses the other one.
1There's no real difference between this "function-like thingy" and an actual function except that this particular function-like thingy doesn't have a name by which you can invoke it. That's more or less what it means to have first-class functions.
The original form of this is:
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
Let's rewrite this with a few type names and other syntactic changes that leave the core of the code the same. First, let's make a name that means func(int) int
:
type adderClosure func(int) int
Then we can use that to rewrite adder
s first line:
func adder() adderClosure {
...
}
Now let's make a local variable inside adder to hold the function we're going to return. To be explicit and redundant, we can use this type again:
var ret adderClosure // not good style: just for illustration
Let's now assign that variable to our closure by doing this:
sum := 0
ret = func(x int) int {
sum += x
return sum
}
and then we can return ret
to return the closure. Here's the complete code on the Go Playground.
Upvotes: 2
Reputation: 2373
The sum
variable is inside each of the two closures when you assign pos
and neg
. The sum
in the pos
closure is updated by adding 1, 2, 3, 4 (fibonacci style) while the sum
in the neg
closure is updated by subtracting 2*1, 2*2, 2*3, 2*4 in each of the loop iterations.
Or, in more detail:
pos := adder()
assigns to pos
a function having a closure on sum
where sum
is 0 to begin. Then whenever you call the function pos
, it will updated sum
accordingly. The exact same is true with neg
, and any other similar assignment.
Here's some similar (simpler) code in JavaScript to run in your browser console:
function adder() {
var sum = 0;
return function(i) {
sum += i;
return sum;
}
}
var pos = adder();
console.log( pos(1) ); // add 1 to 0 (1)
console.log( pos(2) ); // add 2 to 1 (3)
console.log( pos(3) ); // add 3 to 3 (6)
console.log( pos(4) ); // add 4 to 6 (10)
Here's some background about Closures in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Hope this helps.
Upvotes: 0