这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
闭包的概念
闭包(Closure)是引用了自由变量的函数,这个函数存储了一个函数和与该函数相关联的函数。
举例
[官方文档](Go by Example: Closures)
// Go supports [_anonymous functions_](https://en.wikipedia.org/wiki/Anonymous_function),
// which can form <a href="https://en.wikipedia.org/wiki/Closure_(computer_science)"><em>closures</em></a>.
// Anonymous functions are useful when you want to define
// a function inline without having to name it.
package main
import "fmt"
// This function `intSeq` returns another function, which
// we define anonymously in the body of `intSeq`. The
// returned function _closes over_ the variable `i` to
// form a closure.
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
// We call `intSeq`, assigning the result (a function)
// to `nextInt`. This function value captures its
// own `i` value, which will be updated each time
// we call `nextInt`.
nextInt := intSeq()
// See the effect of the closure by calling `nextInt`
// a few times.
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
// To confirm that the state is unique to that
// particular function, create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}
分析
观察函数inSeq(),发现该函数的内部定义了一个变量i,它将返回一个匿名函数,这个函数持有对外部变量i的引用。
程序入口函数处定义了两个变量nextInt和newInts,它们都分别持有对intSeq()函数中内部匿名函数的引用,执行这段程序,结果为:
1
2
3
1
可以发现,每次执行nextInt(),也就是inSeq()的内部匿名函数时,输出的结果都为上一次执行结果的+1,变量i并没有被回收,而是保留了下来供内部的匿名函数使用。
nextInt就是我们创建的一个闭包,这个闭包保留了一些状态,在这个例子中,状态就是变量i。
因此newInts也是一个闭包,但这个闭包是重新创建的,并不与闭包nextInt共享状态,所以它的输出结果就是1。
总结
- 如果一个函数用到了它作用域外面的变量,那么这个变量和这个函数之间的环境就叫闭包。
- 能够读取其他函数内部变量的函数,就是闭包。(内部的匿名函数持有其外部变量)
- 闭包是一个有状态的函数。