函数编程之闭包漫谈(Closure)
函数是什么
>>> def ExFunc(n):
sum=n
def InsFunc():
return sum+1
return InsFunc
>>> myFunc=ExFunc(10)
>>> myFunc()
>>> myAnotherFunc=ExFunc(20)
>>> myAnotherFunc()
>>> myFunc()
>>> myAnotherFunc()
>>>
在这段程序中,函数InsFunc是函数ExFunc的内嵌函数,并且是ExFunc函数的返回值。我们注意到一个问题:内嵌函数InsFunc中引用到外层函数中的局部变量sum,IronPython会这么处理这个问题呢?先让我们来看看这段代码的运行结果。当我们调用分别由不同的参数调用ExFunc函数得到的函数时(myFunc(),myAnotherFunc()),得到的结果是隔离的,也就是说每次调用ExFunc函数后都将生成并保存一个新的局部变量sum。其实这里ExFunc函数返回的就是闭包。
『纯』的函数是没有状态的,加入了闭包以后就变成有状态的了,相对于一个有成员变量的类实例来说,闭包中的状态值不是自己管理,可以认为是『上帝』在管理。
- 动态作用域,词法作用域
- 把数据和作用域绑定到一起就是闭包。
- 将一个上下文的私有变量的生命周期延长的机制。
- 调用了局部变量的函数就是闭包!
引用环境
按照命令式语言的规则,ExFunc函数只是返回了内嵌函数InsFunc的地址,在执行InsFunc函数时将会由于在其作用域内找不到sum变量而出错。而在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。现在给出引用环境的定义就容易理解了:引用环境是指在程序执行中的某个点所有处于活跃状态的约束(一个变量的名字和其所代表的对象之间的联系)所组成的集合。闭包的使用和正常的函数调用没有区别。
由于闭包把函数和运行时的引用环境打包成为一个新的整体,所以就解决了函数编程中的嵌套所引发的问题。如上述代码段中,当每次调用ExFunc函数时都将返回一个新的闭包实例,这些实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
val string = "HelloWorld"
// 闭包:函数的运行环境
// 函数的作用域没有被释放,作用域包含了函数运行的状态、变量、本地类、本地函数,这个作用域就是闭包
fun makeFun(): ()->Unit // ()->Unit 函数是 makeFun() 的返回值,即函数的返回值是一个函数
// makeFun()的函数体
{
var count = 0
return fun(){
println(++count)
}
}
fun fibonacci(): Iterable<Long>{
var first = 0L
var second = 1L
return Iterable {
object : LongIterator(){
override fun nextLong(): Long {
val result = second
second += first
first = second - first
return result
}
override fun hasNext() = true
}
}
}
fun main(args: Array<String>) {
val add5 = add(5)
println(add5(2))
}
//fun add(x: Int) = fun(y: Int) = x + y
fun add(x: Int): (Int)-> Int{
data class Person(val name: String, val age: Int)
return fun(y: Int): Int{
return x + y
}
}