【问题标题】:Go resetting closure variable去重置闭包变量
【发布时间】:2018-01-24 23:56:02
【问题描述】:

我在这里遇到了 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() {

    // 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())
}

这个输出仍然是 1,2,3,1。是否每次调用 main() 中的 nextInt() 时都不会重新分配 intSeq() 中的变量“i”?

【问题讨论】:

    标签: go closures anonymous-function


    【解决方案1】:

    看看你是如何实现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 创建一个新值)。

    我希望澄清一下。

    【讨论】:

      【解决方案2】:

      不,它没有。这就是关闭的重点。您正在初始化一个整数变量并将其存储在堆中以供intSeq() 函数返回的函数使用。 nextInt() 函数中没有发生变量初始化

      您将获得一个新函数,每次调用 intSeq() 时都会使用从 0 开始的新序列计数器

      编辑:添加到此是获取当前行为的不好方法。更好的方法是创建一个包含方法nextInt() int 的新sequence 类型。例如:

      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】:

        i := *new(int) 没有意义。那行说:

        1. 分配一个新的int
        2. 创建指向它的指针
        3. 取消引用指针
        4. 将值分配给i

        这与i := 0var int i 没有什么不同,但在创建、取消引用和丢弃永远不会被使用的指针的中间有一个额外的步骤。

        如果您想要一个指向 int 的指针,请使用 i := new(int)*new 任何地方都是毫无意义的调用和代码异味。

        【讨论】:

        • 同意。尽管我很想对此表示赞同,但从技术上讲,这并不是问题的答案,所以我必须坚持积极的评论;)
        猜你喜欢
        • 2017-09-17
        • 1970-01-01
        • 1970-01-01
        • 2017-09-27
        • 2014-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多