go语言闭包
1、闭包的定义
函数可以嵌套定义(嵌套的函数一般为匿名函数),即在一个函数内部可以定义另一个函数。Go语言通过匿名函数支持闭包,C++不支持匿名函数,在C++11中通过Lambda表达式支持闭包。
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。
闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,函数代码在函数被定义后就确定,不会在执行时发生变化,所以一个函数只有一个实例。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。约束是指一个变量的名字和其所代表的对象之间的联系。由于在支持嵌套作用域的语言中,有时不能简单直接地确定函数的引用环境,因此需要将引用环境与函数组合起来。
2、闭包的本质
闭包是包含*变量的代码块,变量不在代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。由于*变量包含在代码块中,所以只要闭包还被使用,那么*变量以及引用的对象就不会被释放,要执行的代码为*变量提供绑定的计算环境。
闭包可以作为函数对象或者匿名函数。支持闭包的多数语言都将函数作为第一级对象,即函数可以存储到变量中作为参数传递给其它函数,能够被函数动态创建和返回。
func add(n int) func(int) int {
sum := n
f := func(x int) int {
var i int = 2
sum += i * x
return sum
}
return f
}
add函数中函数变量为f,*变量为sum,同时f为sum提供绑定的计算环境,sum和f组成的代码块就是闭包。add函数的返回值是一个闭包,而不仅仅是f函数的地址。在add闭包函数中,只有内部的匿名函数f才能访问局部变量i,而无法通过其它途径访问,因此闭包保证了i的安全性。
当分别用不同的参数(10, 20)注入add函数而得到不同的闭包函数变量时,得到的结果是隔离的,即每次调用add函数后都将生成并保存一个新的局部变量sum。
在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。
当每次调用add函数时都将返回一个新的闭包实例,不同实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
从形式上看,匿名函数都是闭包。
函数只是一段可执行代码,编译后就固定,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数。
对象是附有行为的数据,而闭包是附有数据的行为。
3、闭包的使用
闭包经常用于回调函数,当IO操作(例如从网络获取数据、文件读写)完成的时候,会对获取的数据进行某些操作,操作可以交给函数对象处理。
除此之外,在一些公共的操作中经常会包含一些差异性的特殊操作,而差异性的操作可以用函数来进行封装。
package main
import "fmt"
func adder() func(int) int {
sum := 0
f := func(x int) int {
sum += x
return sum
}
return f
}
func main() {
sum := adder()
for i := 0; i < 10; i++ {
fmt.Println(sum(i))
}
}
四、闭包的应用
package main
import "fmt"
//普通闭包
func adder() func(int) int {
sum := 0
return func(v int) int {
sum += v
return sum
}
}
//无状态、无变量的闭包
type iAdder func(int) (int, iAdder)
func adder2(base int) iAdder {
return func(v int) (int, iAdder) {
return base + v, adder2(base + v)
}
}
//使用闭包实现斐波那契数列
func Fibonacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
func main() {
//普通闭包调用
a := adder()
for i := 0; i < 10; i++ {
var s int =a(i)
fmt.Printf("0 +...+ %d = %d\n",i, s)
}
//状态 无变量的闭包 调用
b := adder2(0)
for i := 0; i < 10; i++ {
var s int
s, b = b(i)
fmt.Printf("0 +...+ %d = %d\n",i, s)
}
//调用斐波那契数列生成
fib:=Fibonacci()
fmt.Println(fib(),fib(),fib(),fib(),fib(),fib(),fib(),fib())
}
本文转自 https://blog.51cto.com/9291927/2130303
上一篇: Go语言---bytes包
下一篇: Go语言---strconv包