循序渐进:闭包实现斐波那契数列生成器
1 简介
- 什么是 Golang 中的闭包?
当 Go 中的匿名函数可以访问其周围环境时,就会发生闭包。然后它可以保持自己的独特状态。
然后,当我们创建函数的新实例时,之前实例的状态将是独立的。
这将为函数创建一个新属性,以了解其周围环境。此属性称为 闭包closure 属性。
2 变量的范围
匿名函数,嵌套函数 和 返回函数都可以访问局部块变量,如果不使用局部变量隔离数据,那么就使用全局变量(package var)。
var x = 0
func increment() int {
x++
return x
}
func main() {
fmt.Println(increment())
fmt.Println(increment())
}
全局变量 x 未作为参数传递给匿名函数,但该函数可以访问它。
在这个例子中,有一个小问题,因为将在package中定义的任何其他函数都可以访问全局变量 x,并且它可以在不调用 increment 函数的情况下更改它。
而闭包还提供了另一个方面,即数据隔离,我们来了解它。
func main() {
x := 42
fmt.Println(x)
{
fmt.Println(x)
y := "功劳属于在擂台上的人。"
fmt.Println(y)
}
// fmt.Println(y) // outside scope of y
}
可以看到,我们也可以直接在main函数使用匿名函数,如果要在外部函数使用 闭包内部的变量就会报错。
3 匿名函数和嵌套函数
- 嵌套函数
当我们在函数中创建另一个函数时,这称之为嵌套函数,以下main函数中通过创建匿名函数访问main函数变量x。
可以直接在函数中创建内部函数并且立即调用它。如此在另一个函数中创建一个函数。这称为嵌套函数。例如
package main
import "fmt"
// outer function
func Hello(name string) {
// inner function
var displayName = func() {
fmt.Println("Hi", name)
}
// call inner function
displayName()
}
func main() {
// call outer function
Hello("Frank") // Hi Frank
}
在该示例中,我们在函数Hello内部创建了一个匿名函数displayName = func(){…},
在这里displayName它是一个嵌套函数。嵌套函数displayName的工作方式与普通函数类似。它在函数Hello内部。
这里 是一个嵌套函数。嵌套函数的工作方式与普通函数类似。它在函数 var displayName = func() {…}displayName()
4 返回匿名函数
同样的,我们可以设置匿名函数为外部函数的返回值,也就是可以创建一个返回匿名函数的函数
package main
import "fmt"
func Hello() func() {
return func() {
fmt.Println("Hi Frank")
}
}
func main() {
h1 := Hello()
h1()
}
输出
Hi Frank
在上面的示例中,我们创建了函数 Hello()。
func Hello() func() {...}
此处,大括号之前表示该函数返回另一个函数。func()
此外,如果你查看这个函数的 return 语句,我们可以看到该函数正在返回一个函数。
从 main() 中,我们调用函数Hello()。
h1 := Hello()
在这里,返回的函数现在被分配给变量。因此,执行嵌套的匿名函数。
5 闭包实现斐波那契数列输出
那么如何使用闭包打印斐波那契数列,同时隔离数据呢?
package main
import "fmt"
func fib() func() int {
a := 1
f := 0
// returns inner function
return func() int {
f, a = a, f+a
return f
}
}
func main() {
// call the outer function
fdd := fib()
// call the inner function
for i := 0; i < 10; i++ {
fmt.Println("f :", fdd())
}
// call the outer function again
fdd2 := fib()
fmt.Println(fdd2())
}
此代码执行外部函数并返回 斐波那契数的闭包。
这就是为什么我们可以在完成外部函数fib后, 可以连续通过fdd 访问 f 的变量。
而再次调用外部fib函数后,有fdd2 := fib(),重新得到1
在上面的示例中,该fib()函数返回一个匿名函数,
return func() int {
f, a = a, f+a
return f
}
该函数将计算原有的变量 a和f,每次调用该匿名函数都将a的值赋予f,并修改其函数内部的变量a,然后并返回f。
这表明闭包数据是彼此隔离的。
6 小结
每次调用闭包外部函数时都会返回一个新的闭包。在这里,每个返回的闭包都是彼此独立的,并且一个闭包的更改不会影响另一个闭包。
这有助于我们在彼此隔离的情况下处理多个数据。比如让我们看前面这个斐波那契数列的例子。
在需要数据隔离的地方,该闭包属性被广泛使用。它提供的数据状态使它们在这方面提供了极大的帮助。当我们想创建一个状态封装的函数时,我们使用闭包来实现。
- 点赞
- 收藏
- 关注作者
评论(0)