GO是支持函数式编程的,在GO中,函数是一等公民,它可以作为变量被赋值,作为参数被传递到其它函数中。
那么既然能够将函数作为变量,GO就一定是支持闭包
的。
闭包概念
什么是闭包呢?其实很简单,我们都知道,变量是有其作用域
的。例如,在函数中声明定义的变量就只能够在当前函数中使用,当函数结束时,该变量空间就会被释放,外部无法再使用。
但是,闭包允许我们将变量的作用域进行扩充。当我们的函数会返回另外一个函数时(不管是直接返回出去,还是保存在其他变量中间接返回出去),这个被返回的函数如果引用到一些内部的变量,那么这些内部的变量值将会和被返回的函数一起“打包”,作为一个整体返回出去。
这样,在外部,不仅可以使用到被返回的函数,也可以使用到本应该是不可见的,那些被一起打包返回的内部变量的值。
通俗地说,这其实是一个“借刀杀人”的过程。例如你想访问函数fun1
的某个内部变量a
的值,但是fun1
没有直接返回这个值。这在一般情况下就无法实现了:
package main
import "fmt"
func fun1() {
a := 10
fmt.Println("fun1 a =", a)
}
func main() {
// 这里无法直接访问fun1中的a
fmt.Println("fun1 a =", a) // 编译错误:undefined: a
}
但是,如果我们让fun1
返回另外一个函数(假设为fun2
),这个函数使用到了变量a
。因为fun2
被返回出去了,外部能够访问了,那么变量a
就会和fun2
作为闭包一起被返回出去,外部就能获取a
的值了。我们通过第三者fun2
访问到了a
:
package main
import "fmt"
// 需要被闭包返回出去的函数
type fun2 func() int
func fun1() fun2 {
a := 10
return func() int {
// 将fun1中的a返回出去
return a
}
}
func main() {
// 先获取fun2
fun2 := fun1()
// 从fun2获取a
a := fun2()
fmt.Println("a =", a)
}
这就是闭包最简单的用法了。
闭包的作用(通过例子学习)
如果这样,你可能会想:那闭包有什么用呢?我为什么不直接返回a
,还需要费劲地通过一个函数来把它返回出去?
当然,上面的例子没有什么意义,只是为了让大家简单地认识闭包。我们来看一个更加具体的例子:通过闭包实现求算斐波那契数列。
和传统的求斐波那契不一样,我们想实现这么个效果:
- 获取一个fib()函数,每次调用该函数,都能返回下一个斐波那契数。
- 例如,运行
fmt.Println(fib(), fib(),