Reputation: 413
I came upon an example of closures in Go here: https://gobyexample.com/closures
It gives a pretty straight-forward example of closure scoping in Go. I changed how i is initialized from "i := 0" to "i := *new(int)".
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
func main() {
// We call `intSeq`, assigning the result (a function)
// to `nextInt`. This function value captures its
// own `i` value, which will be updated each time
// we call `nextInt`.
nextInt := intSeq()
// See the effect of the closure by calling `nextInt`
// a few times.
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
// To confirm that the state is unique to that
// particular function, create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}
The output of this is still 1, 2, 3, 1. Does the variable 'i' in intSeq() not get reallocated everytime nextInt() in main() is called?
Upvotes: 0
Views: 1261
Reputation: 12383
Take a look at how you implemented intSeq
.
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
The initialization of i
is outside of the function it returns.
So the only time a new pointer is allocated is when you actually call intSeq
.
Since you are doing that just two times, that's how many different pointers you got.
That explains why the value is not reset when you just call nextInt
(note that executing nextInt
means just executing the function returned, which looks like:
func() int {
i += 1
return i
}
That would not reset the value of i
but rather keep incrementing it (until you create a new one by calling intSeq
again).
I hope that clarifies.
Upvotes: 3
Reputation: 2291
No it doesn't. That's the point of the closure. You are initializing an integer variable and storing it on the heap for use by the function the intSeq()
function returns. There is no variable initialization happening in the nextInt()
function
You will get a new function that uses a new sequence counter starting at 0 for each call to intSeq()
Edit: to add to this this is a bad way to get the current behavior. A better way would be to create a new sequence
type that contains the method nextInt() int
. E.g.:
type Sequence struct {
counter int
}
func (s *Sequence) nextInt() int {
s.counter++
return s.counter
}
func main() {
intSeq := new(Sequence)
fmt.Println(intSeq.nextInt())
fmt.Println(intSeq.nextInt())
fmt.Println(intSeq.nextInt())
}
Upvotes: 2
Reputation: 46423
There is no point in doing i := *new(int)
. That line says:
int
i
This is no different from i := 0
or var int i
, but there's the extra step in the middle of creating, dereferencing, and discarding the pointer that never gets used.
If you want a pointer to an int, use i := new(int)
. *new
anywhere is a pointless invocation and a code smell.
Upvotes: 0