1、闭包函数
闭包并不只是一个go中的概念,在函数式编程中应用比较广泛。
首先看一下WIKI上对闭包的解释:
在计算科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用自由变量的函数。这个被引用的自由变量将和这个函数一起存在,即使已经离开了创造它的环境也不例外。所以,有另外一种说法认为闭包是由函数和与其他相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。这样的一个函数我们称之为闭包。闭包需要满足以下三个条件:
- 必须是一个嵌套函数
- 必须返回嵌套函数
- 嵌套函数必须引用外部非全局的局部自由变量
案例1:
package mainimport "fmt"func adder() func(int) int {sum := 0a := func(x int) int { //1. 嵌套函数sum += x // 3. 引用了非全局的局部自由变量 sumreturn sum}return a // 2. 返回嵌套函数}func main() {fmt.Println(adder()(100))}
注意:按道理来讲的话,执行了adder() 这个函数之后其实 sum 这个变量就已经消亡了,但是使用了闭包了,所以 sum 这个变量就被保护了下来,被带到匿名函数里面去了,所以闭包的作用就是很好的保护了 sum 这个自由变量,而且保证了数据的一致性。
2、装饰函数
案例1:计算函数调用次数
package mainimport "fmt"func counter(f func()) func() int {n := 0number := func() int {f()n++return n}return number}// 测试调用的函数func foo() {fmt.Println("foo function 调用")}func main() {foo := counter(foo) // 返回值重新赋值给foofoo()foo()n := foo()fmt.Println(n)}
案例2:计算函数运行时间
package mainimport ("fmt""time")func timer(f func(x,y int)) func(int, int) {wapper := func(x, y int) {timeBefore := time.Now().Unix()f(x, y)timeEnd := time.Now().Unix()fmt.Println("运行时间: ", timeEnd-timeBefore)}return wapper}func add(x, y int) {fmt.Printf("%d+%d=%d", x, y, x+y)time.Sleep(time.Second * 2)}func mul(x, y int) {fmt.Printf("%d*%d=%d", x, y, x*y)time.Sleep(time.Second * 3)}func main() {//fmt.Println(reflect.TypeOf(add)) // func(int,int)add := timer(add)add(1, 2)mul := timer(mul)mul(3, 4)}
价值:能够动态灵活的创建以及传递函数,体现出函数式编程的特点。所以在一些场合,我们就多了一种编码方式的选择,适当的使用闭包可以使得我们的代码简洁高效
3、闭包练习
package mainimport "fmt"func makeFun(i int) func() {return func() {fmt.Println(i)}}func makeFun2() func(i int) {return func(i int) {fmt.Println(i)}}func main() {// 版本1/*var fn [10]func()for i := 0; i < len(fn); i++ {fn[i] = func() {fmt.Println(i)}}for _, f := range fn {f()}*/// 版本2/*var fn [10]func()for i := 0; i < len(fn); i++ {fn[i] = func() {fmt.Println(i)}}for i := 0 ; i < len(fn); i++ {fn[i]()}*/// 版本3/*var fn [10]func()for i := 0; i < len(fn); i++ {fn[i] = func() {fmt.Println(i) // 对外部自由变量的引用,根本也是一个闭包,i保留的是最后一次赋值结果10}}for j := 0 ; j < len(fn); j++ {fn[j]()}*/// 版本4/*var fn [10]func()var i intfor i = 0; i < len(fn); i++ {fn[i] = func() {fmt.Println(i)}}for i = 0; i < len(fn); i++ {fn[i]()}*/// 版本5/*var fn [10]func()for i := 0; i < len(fn); i++ {fn[i] = makeFun(i)}for _, f := range fn {f()}*/// 版本6/*var fn [10]func(int)for i := 0; i < len(fn); i++ {fn[i] = makeFun2()}for i, f := range fn {f(i)}*/}
