Go关闭变量范围 [英] Go closure variable scope
问题描述
我正在阅读CreateSpace 2012年编程入门
和第86页我发现了这个邪恶的魔法
func makeEvenGenerator()func()uint {
i:= uint(0)
return func {
ret = i
i + = 2
return
}
}
//这里叫做
nextEven: = makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())
1)为什么 i
不会重置?
2)是 nextEven()
返回和 uint
或者是 Println
这么聪明,它可以处理一切?
为了清楚起见,这两个函数:
func makeEvenGenerator()func()uint {//将这个工厂命名为
i: = uint(0)
return func()(ret uint){//称为闭包
ret = i
i + = 2
return
}
}
工厂返回闭包–函数是Go中的头等公民,即它们可以是右手表达式,例如:
f:= func fmt.Println(f called called); }
f()// printsf被调用
代码,闭包覆盖了工厂的上下文,这被称为词法范围。这就是为什么变量 i
在闭包中可用,而不是作为副本,而是作为 i
本身的引用。
闭包使用名为 ret
的命名的返回值。这意味着在闭包内你将隐式声明 ret
,在 return
的时候, ret
将被退回。
此行:
ret = i
将分配当前值 i
到 ref
。它不会更改 i
。但是,此行:
i + = 2
将会在下一次调用闭包时更改 i
的值。
这里你会发现一个小例子写在一起为你。这不是非常有用,但说明了封闭的范围,目的和使用在我看来很好:
package main
importfmt
func makeIterator(s [] string)func()func()string {
i:= 0
return func() string {
if i == len(s){
return nil
}
j:= i
i ++
return func()string {
return s [j]
}
}
}
func main(){
i:= makeIterator {hello,world,this,is,dog})
for c:= i c!= nil; c = i(){
fmt.Println(c())
}
}
I'm reading 'CreateSpace An Introduction to Programming in Go 2012'
and on page 86 I found this evil magic
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) Why is
i
not resetting ? 2) isnextEven()
returning anduint
or isPrintln
so smart that it can work with everything ?解决方案For the sake of clarity, I'll assign names to both functions:
func makeEvenGenerator() func() uint { // call this "the factory" i := uint(0) return func() (ret uint) { // call this "the closure" ret = i i += 2 return } }
The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:
f := func() { fmt.Println("f was called"); } f() // prints "f was called"
In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable
i
is available inside the closure, not as a copy but as a reference toi
itself.The closure uses a named return value called
ret
. What this means is that inside the closure you'll have implicitly declaredret
and at the point ofreturn
, whatever valueret
has will be returned.This line:
ret = i
will assign the current value of
i
toref
. It will not changei
. However, this line:i += 2
will change the value of
i
for the next time the closure is called.
Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:
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关闭变量范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!