我正在阅读“ 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如此聪明以至于它可以与所有东西配合使用?
i
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中的一等公民,即它们可以是右手表达式,例如:
f := func() { fmt.Println("f was called"); } f() // prints "f was called"
在您的代码中,闭包环绕工厂的上下文,这称为 词法作用域 。这就是变量i在闭包内部可用的原因,而不是作为副本而是作为对i自身的引用。
封闭使用 命名返回值 叫ret。这意味着在闭包内部您将隐式声明ret,在时return,ret将返回任何值。
ret
return
这行:
ret = i
会将的当前值分配i给ref。它不会改变i。但是,这一行:
ref
i += 2
将i在下次调用闭包时更改的值。
在这里,您会找到我为您写的一个封闭示例。我认为它不是非常有用,但可以很好地说明闭包的范围,目的和用法:
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()) } }