Go语言闭包
1、闭包的概念
闭包(Closure)是词法闭包(Lexical Closure)的简称。是由函数和与其相关的引用环境组合而成的实体。在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。函数 + 引用环境 = 闭包。闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。
闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。闭包在某些编程语言中被称为 Lambda 表达式。
函数本身不存储任何信息,只有与引用环境结合后形成的闭包才具有“记忆性”。函数是编译器静态的概念,而闭包是运行期动态的概念。
对象是附有行为的数据,而闭包是附有数据的行为。
2、闭包的优点
1) 加强模块化
闭包有益于模块化编程,便于以简单的方式开发较小的模块,从而提高开发速度和程序的可复用性。和没有使用闭包的程序相比,使用闭包可将模块划分得更小。比如要计算一个数组中所有数字的和,只需要循环遍历数组,把遍历到的数字加起来就行了。如果现在要计算所有元素的积,又或者要打印所有的元素呢?解决这些问题都要对数组进行遍历,如果是在不支持闭包的语言中,程序员不得不一次又一次重复地写循环语句。而这在支持闭包的语言中是不必要的。这种处理方法多少有点像回调函数,不过要比回调函数写法更简单,功能更强大。
2) 抽象
闭包是数据和行为的组合,这使得闭包具有较好的抽象能力。3) 简化代码
一个编程语言需要以下特性来支持闭包。- 函数是一阶值(First-class value,一等公民),即函数可以作为另一个函数的返回值或参数,还可以作为一个变量的值;
- 函数可以嵌套定义,即在一个函数内部可以定义另一个函数;
- 允许定义匿名函数;
- 可以捕获引用环境,并把引用环境和函数代码组成一个可调用的实体。
接下来通过三个示例的对比来更清晰地了解闭包的作用。
【示例】没有使用闭包进行计数的代码。
package main import "fmt" func main() { for i := 0; i < 5; i++ { fmt.Printf("i=%d \t", i) fmt.Println(add2(i)) } } func add2(x int) int { sum := 0 sum += x return sum }运行结果如下:
i=0 0
i=1 1
i=2 2
i=3 3
i=4 4
【示例】使用闭包函数实现计数器。
package main import "fmt" func main() { pos := adder() for i := 0; i < 10; i++ { fmt.Printf("i=%d \t", i) fmt.Println(pos(i)) } fmt.Println("--------------------") for i := 0; i < 10; i++ { fmt.Printf("i=%d \t", i) fmt.Println(pos(i)) } } func adder() func(int) int { sum := 0 return func(x int) int { fmt.Printf("sum1=%d \t", sum) sum += x fmt.Printf("sum2=%d \t", sum) return sum } }运行结果如下:
i=0 sum1=0 sum2=0 0
i=1 sum1=0 sum2=1 1
i=2 sum1=1 sum2=3 3
i=3 sum1=3 sum2=6 6
i=4 sum1=6 sum2=10 10
i=5 sum1=10 sum2=15 15
i=6 sum1=15 sum2=21 21
i=7 sum1=21 sum2=28 28
i=8 sum1=28 sum2=36 36
i=9 sum1=36 sum2=45 45
--------------------
i=0 sum1=45 sum2=45 45
i=1 sum1=45 sum2=46 46
i=2 sum1=46 sum2=48 48
i=3 sum1=48 sum2=51 51
i=4 sum1=51 sum2=55 55
i=5 sum1=55 sum2=60 60
i=6 sum1=60 sum2=66 66
i=7 sum1=66 sum2=73 73
i=8 sum1=73 sum2=81 81
i=9 sum1=81 sum2=90 90
package main import "fmt" func main() { myfunc := Counter() // fmt.Printf("%T\n", myfunc) fmt.Println("myfunc", myfunc) // 调用 myfunc 函数,i变量自增 1 并返回 fmt.Println(myfunc()) fmt.Println(myfunc()) fmt.Println(myfunc()) // 创建新的函数 nextNumber1,并查看结果 myfunc1 := Counter() fmt.Println("myfunc1", myfunc1) fmt.Println(myfunc1()) fmt.Println(myfunc1()) } //计数器,闭包函数 func Counter() func() int { i := 0 res := func() int { i += 1 return i } // fmt.Printf("%T, %v \n", res, res) fmt.Println("Counter 中的内部函数:", res) return res }运行结果如下:
Counter 中的内部函数: 0x49ac50
myfunc 0x49ac50
1
2
3
Counter 中的内部函数: 0x49ac50
myfunc1 0x49ac50
1
2
声明:《Go系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。