我正在阅读'CreateSpace转到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())
Run Code Online (Sandbox Code Playgroud)
1)为什么i不重置?2)nextEven()回归和/ uint或是Println如此聪明,它可以与一切工作?
thw*_*hwd 11
为了清楚起见,我将为这两个函数指定名称:
func makeEvenGenerator() func() uint { // call this "the factory"
i := uint(0)
return func() (ret uint) { // call this "the closure"
ret = i
i += 2
return
}
}
Run Code Online (Sandbox Code Playgroud)
工厂返回闭包 - 函数是Go中的一等公民,即它们可以是右手表达式,例如:
f := func() { fmt.Println("f was called"); }
f() // prints "f was called"
Run Code Online (Sandbox Code Playgroud)
在您的代码中,闭包包装了工厂的上下文,这称为词法作用域.这就是变量i在闭包内可用的原因,不是作为副本而是作为对i自身的引用.
封闭使用命名返回值叫ret.这意味着在闭包内你将隐式声明,ret并且在return任何时候,ret将返回任何值.
这一行:
ret = i
Run Code Online (Sandbox Code Playgroud)
将分配的电流值i来ref.它不会改变i.但是,这一行:
i += 2
Run Code Online (Sandbox Code Playgroud)
将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())
}
}
Run Code Online (Sandbox Code Playgroud)
1)为什么我没有重置?
Go中的闭包通过引用捕获变量.这意味着内部函数i在外部作用域中保存对变量的引用,并且每次调用它都会访问同一个变量.
2)nextEven()返回和uint或Println如此聪明,它可以与一切工作?
fmt.Println()(沿fmt.Print(),fmt.Fprint()等等)可以工作大多数类型.它以"默认格式"打印其参数.fmt.Printf()使用%v动词打印是一回事.