英文:
Go resetting closure variable
问题
我在这里找到了一个关于Go语言闭包的例子:https://gobyexample.com/closures
它给出了一个相当直观的Go语言闭包作用域的例子。我将初始化i的方式从"i := 0"改为"i := *new(int)"。
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
func main() {
// 调用`intSeq`,将结果(一个函数)赋值给`nextInt`。这个函数值捕获了它自己的`i`值,每次调用`nextInt`时都会更新它。
nextInt := intSeq()
// 通过多次调用`nextInt`来观察闭包的效果。
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
// 为了确认状态是特定函数独有的,创建并测试一个新的函数。
newInts := intSeq()
fmt.Println(newInts())
}
这段代码的输出仍然是1、2、3、1。难道intSeq()函数中的变量i
在main()函数中每次调用nextInt()时不会重新分配内存空间吗?
英文:
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?
答案1
得分: 3
请看一下你是如何实现intSeq
的。
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
i
的初始化在它返回的函数之外。
所以只有当你实际调用intSeq
时才会分配一个新的指针。
由于你只调用了两次,所以你得到了两个不同的指针。
这就解释了为什么当你只调用nextInt
时值不会被重置(注意,执行nextInt
只是执行返回的函数,它看起来像这样:
func() int {
i += 1
return i
}
这不会重置i
的值,而是继续递增它(直到你通过再次调用intSeq
创建一个新的值)。
希望这样解释清楚了。
英文:
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.
答案2
得分: 2
不,它不会。这就是闭包的作用。你正在初始化一个整数变量,并将其存储在堆上,以供intSeq()
函数返回的函数使用。在nextInt()
函数中没有进行变量初始化。
每次调用intSeq()
时,你将获得一个使用新的序列计数器从0开始的新函数。
编辑:此外,这是一种获取当前行为的不好方式。更好的方法是创建一个新的sequence
类型,其中包含方法nextInt() int
。例如:
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())
}
英文:
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())
}
答案3
得分: 0
在执行i := *new(int)
没有任何意义。这行代码的含义是:
- 分配一个新的
int
变量 - 创建一个指向该变量的指针
- 解引用指针,获取变量的值
- 将该值赋给
i
这与i := 0
或var int i
没有任何区别,但是在创建、解引用和丢弃指针之间多了一步操作,而这个指针从未被使用过。
如果你想要一个指向int的指针,可以使用i := new(int)
。在任何地方使用*new
都是一个无意义的调用,也是一种代码异味。
英文:
There is no point in doing i := *new(int)
. That line says:
- Allocate a new
int
- Create a pointer to it
- Dereference the pointer
- Assign the value to
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论