function createCountdownTimer(second) local ms=second * 1000; local function countDown() ms = ms - 1; return ms; end return countDown; endtimer1 = createCountdownTimer(1); for i=1,3 do print(timer1()); end print("------------"); timer2 = createCountdownTimer(1); for i=0,2 do print(timer2()); end
999 998 997 ------------ 999 998 997
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; end function obj.GetID() return data.id; end function obj.SetName(name) data.name=name; end function obj.SetID(id) data.id=id end return 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: 100 o2's id: 7 --o1's name: Sam o2's name: Lucy
实现方式:把需要隐藏的成员放在一张表里,把该表作为成员函数的upvalue。
局限性:基于对象的实现不涉及继承及多态。但另一方面,脚本编程是否需要继承和多态要视情况而定。
元表
t = {} m = { a = " and ", b = "Li Lei", c = "Han Meimei" } setmetatable(t, { __index = m}) --表{ __index=m }作为表t的元表 for k, v in pairs(t) do --穷举表t print(v) end print("-------------") print(t.b, t.a, t.c)--输出结果 --------------- --Li Lei and Han Meimei
function add(t1, t2) --‘#'运算符取表长度 assert(#t1 == #t2) local length = #t1 for i = 1, length do t1[i] = t1[i] + t2[i] end return t1 end --setmetatable返回被设置的表 t1 = setmetatable({ 1, 2, 3}, { __add = add }) t2 = setmetatable({ 10, 20, 30 }, {__add = add })
t1 = t1 + t2 for i = 1, #t1 do print(t1[i]) end --11 --22 --33
定义:元表本身只是一个普通的表,通过特定的方法(比如setmetatable)设置到某个对象上,进而影响这个对象的行为;一个对象有哪些行为受到元表影响以及这些行为按照何种方式受到影响是受Lua语言约束的。比如在前面的代码里,两个表对象的加法运算,如果没有元表的干预,就是一种错误;但是Lua规定了元表可以“重载”对象的加法运算符,因此若把定义了加法运算的元表设置到那两个表上,它们就可以做加法了。元表是Lua最关键的概念之一,内容也很丰富,请参考Lua文档了解详情。
元表与C++虚表的比较:如果把表比作对象,元表就是可以改变对象行为的“元”对象。在某种程度上,元表可以与C++的虚表做一类比。但二者还是迥然不同的:元表可以动态的改变,C++虚表是静态不变的;元表可以影响表(以及其他类型的对象)的很多方面的行为,虚表主要是为了定位对象的虚方法(最多再带上一点点RTTI)。
本文向大家介绍python进阶教程之模块(module)介绍,包括了python进阶教程之模块(module)介绍的使用技巧和注意事项,需要的朋友参考一下 我们之前看到了函数和对象。从本质上来说,它们都是为了更好的组织已经有的程序,以方便重复利用。 模块(module)也是为了同样的目的。在Python中,一个.py文件就构成一个模块。通过模块,你可以调用其它文件中的程序。 引入模块 我们先写一个
本文向大家介绍python进阶教程之函数对象(函数也是对象),包括了python进阶教程之函数对象(函数也是对象)的使用技巧和注意事项,需要的朋友参考一下 秉承着一切皆对象的理念,我们再次回头来看函数(function)。函数也是一个对象,具有属性(可以使用dir()查询)。作为对象,它还可以赋值给其它对象名,或者作为参数传递。 lambda函数 在展开之前,我们先提一下lambda函数。可以利用
本文向大家介绍JS函数进阶之prototy用法实例分析,包括了JS函数进阶之prototy用法实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JS函数prototy用法。分享给大家供大家参考,具体如下: 运行结果: 感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果
本文向大家介绍Java进阶教程之String类,包括了Java进阶教程之String类的使用技巧和注意事项,需要的朋友参考一下 之前的Java基础系列中讨论了Java最核心的概念,特别是面向对象的基础。在Java进阶中,我将对Java基础进行补充,并转向应用层面。 大部分编程语言都能够处理字符串(String)。字符串是有序的字符集合,比如"Hello World!"。在Java中,字符串被存储为
本文向大家介绍python进阶教程之循环相关函数range、enumerate、zip,包括了python进阶教程之循环相关函数range、enumerate、zip的使用技巧和注意事项,需要的朋友参考一下 在“循环”一节,我们已经讨论了Python基本的循环语法。这一节,我们将接触更加灵活的循环方式。 range() 在Python中,for循环后的in跟随一个序列的话,循环每次使用的序列元素,
本文向大家介绍Lua的函数环境、包实例讲解,包括了Lua的函数环境、包实例讲解的使用技巧和注意事项,需要的朋友参考一下 定义:函数环境就是函数在执行时所见的全局变量的集合,以一个表来承载。 说明:每个函数都可以有自己的环境,可以通过setfenv来显示的指定一个函数的环境。如果不显示的指定,函数的环境缺省为定义该函数的函数的环境。在前面的代码中,函数foo的缺省环境里没有定义变量g,因此第一次执行