Go闭包变量作用域

标签 go closures

我正在阅读“CreateSpace Go 2012 编程简介”

在第 86 页我发现了这个邪恶的魔法

func makeEvenGenerator() func() uint {
    i := uint(0)

    return func() (ret uint) {
        ret = i
        i += 2
        return
    }
}

// here's how it's called
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())

1) 为什么 i 没有重置? 2) nextEven() 返回和 uint 还是 Println 如此聪明以至于它可以处理所有事情?

最佳答案

为了清楚起见,我将为这两个函数指定名称:

func makeEvenGenerator() func() uint { // call this "the factory"
    i := uint(0)

    return func() (ret uint) { // call this "the closure"
        ret = i
        i += 2
        return
    }
}

工厂返回闭包——函数是 Go 中的一等公民,即它们可以是右 watch 达式,例如:

f := func() { fmt.Println("f was called"); }

f() // prints "f was called"

在您的代码中,闭包覆盖了工厂的上下文,这称为词法作用域。这就是为什么变量 i 在闭包内可用,不是作为副本而是作为对 i 本身的引用。

闭包使用一个名为 ret命名返回值。这意味着在闭包内你将隐式声明 ret 并且在 return 点,无论 ret 有什么值都将被返回.

这一行:

ret = i

会将i的当前值赋给ret。它不会改变i。然而,这一行:

i += 2

将在下次调用闭包时更改 i 的值。


Here你会发现我为你一起写的一个小闭包例子。它不是很有用,但在我看来很好地说明了闭包的范围、目的和用途:

package main

import "fmt"

func makeIterator(s []string) func() func() string {
    i := 0
    return func() func() string {
        if i == len(s) {
            return nil
        }
        j := i
        i++
        return func() string {
            return s[j]
        }
    }
}

func main() {

    i := makeIterator([]string{"hello", "world", "this", "is", "dog"})

    for c := i(); c != nil; c = i() {
        fmt.Println(c())
    }

}

关于Go闭包变量作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19957323/

相关文章:

Javascript 函数内变量的提升

javascript - 为什么 postMessage() 只给我最后一个 DOM 的信息?

json - golang中的结构到复杂的JSON解析

go - 使用 gRPC 的上下文与 SendMsg/RecvMsg 方法发送元数据

go - 如何将响应编写器和 http 请求传递给 Go 中的可执行文件?

循环内的 JavaScript 闭包 – 简单的实际示例

swift - 关闭不需要返回任何东西的集合

javascript - 如何实现在内部范围内缓存/内存请求结果的函数

go - 如何在 Go 中验证 UUID v4?

mongodb - 我怎么知道 mgo session 是否关闭