重置闭包变量

huangapple go评论69阅读模式
英文:

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)没有任何意义。这行代码的含义是:

  1. 分配一个新的int变量
  2. 创建一个指向该变量的指针
  3. 解引用指针,获取变量的值
  4. 将该值赋给i

这与i := 0var int i没有任何区别,但是在创建、解引用和丢弃指针之间多了一步操作,而这个指针从未被使用过。

如果你想要一个指向int的指针,可以使用i := new(int)。在任何地方使用*new都是一个无意义的调用,也是一种代码异味。

英文:

There is no point in doing i := *new(int). That line says:

  1. Allocate a new int
  2. Create a pointer to it
  3. Dereference the pointer
  4. 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.

huangapple
  • 本文由 发表于 2017年8月17日 02:08:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/45720344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定