[Lua]函数闭包

来源:互联网 发布:linux snmpwalk 下载 编辑:程序博客网 时间:2024/04/28 22:02

函数闭包


Lua中的函数是带有词法定界(lexical scoping)的第一类值(first-class values)
第一类值在Lua中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。
词法定界被嵌套的函数可以访问他外部函数中的变量。这一特性给Lua提供了强大的编程能力。
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。

function createCountdownTimer(second)   local ms=second * 1000;   local function countDown()      ms = ms - 1;  return ms;endreturn countDown;endtimer1 = createCountdownTimer(1);for i=1,3 do   print(timer1());endprint("------------");timer2 = createCountdownTimer(1);for i=0,2 do   print(timer2());end
999998997------------999998997
Upvalue:一个函数使用它函数体之外的局部变量(external localvariable)称为这个函数的upvalue
在前面的代码中,函数countDown使用的定义在函数createCountdownTimer中的局部变量ms就是countDown的upvalue,但ms对createCountdownTimer而言只是一个局部变量,不是upvalue。Upvalue是Lua不同于C/C++的特有属性,需要结合代码仔细体会。

函数闭包:一个函数和它所使用的所有upvalue构成了一个函数闭包。

闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量。每次闭包的成功调用后这些外部局部变量都保存他们的值(状态)。当然如果要创建一个闭包必须要创建其外部局部变量。所以一个典型的闭包的结构包含两个函数:一个是闭包自己;另一个是工厂(创建闭包的函数)。迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里。闭包提供的机制可以很容易实现这个任务.

支持闭包特性通常需要一个嵌套函数 , 通过执行嵌套函数来改变所在父函数的局部变量状态 , 父函数保存调用上下文状态 , 而嵌套函数负责修改状态的改变 . (简单来说就是得支持函数嵌套)

Lua函数闭包与C函数的比较:Lua函数闭包使函数具有保持它自己的状态的能力,从这个意义上说,可以与带静态局部变量的C函数相类比。但二者有显著的不同:对Lua来说,函数是一种基本数据类型——代表一种(可执行)对象,可以有自己的状态;但是对带静态局部变量的C函数来说,它并不是C的一种数据类型,更不会产生什么对象实例,它只是一个静态地址的符号名称。

基于对象的实现方式

function create(name,id)    local data={name = name,id=id};    local obj={};    function obj.GetName()      return data.name;endfunction obj.GetID()   return data.id;endfunction obj.SetName(name)   data.name=name;endfunction obj.SetID(id)   data.id=idendreturn obj;endo1 = create("Sam", 001)o2 = create("Bob", 007)o1.SetID(100)print("o1's id:", o1.GetID(), "o2's id:",o2.GetID())o2.SetName("Lucy")print("o1's name:", o1.GetName(),"o2's name:", o2.GetName())--o1's id:100o2's id:7--o1's name:Samo2's name:Lucy
实现方式:把需要隐藏的成员放在一张表里,把该表作为成员函数的upvalue。

局限性:基于对象的实现不涉及继承及多态。但另一方面,脚本编程是否需要继承和多态要视情况而定。


[JS]闭包

0 0
原创粉丝点击