Lua进阶教程之闭包函数、元表实例介绍_Lua

复制代码 代码如下:

function createCountdownTimer(second)
   local ms=second * 1000;
   local function countDown()
      ms = ms - 1;
   return ms;
 end
 return countDown;
end

timer1 = 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;
end

o1 = 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)。

时间: 2024-10-27 02:13:27

Lua进阶教程之闭包函数、元表实例介绍_Lua的相关文章

Lua中的一些常用函数库实例讲解_Lua

前言 这篇文章将会来一些比较轻松的内容,就是简单的介绍一下Lua中几个常用的库.简单的说就是几个API的介绍.所以说,看起来比较容易,也没有多大的分量.就是纯粹的总结.使用库就是为了方便我们的开发,提高开发效率,同时也能保证代码的质量.希望大家以后也不要重复造轮子了. 数学库 数学库(math)由一组标准的数学函数构成.这里主要介绍几个常用的函数,其它的大家可以自行百度解决. 三角函数(sin,cos,tan--) 所有的三角函数都使用弧度单位,可以用函数deg(角度)和rad(弧度)来转换角度

extjs自定义组件函数回调实例介绍

工程里用到了Sencha ExtJs,因为特定的组件原因,导致很多组件得自己.组件定义完成之后的 Success_callback 因为之前没做过,所以这次把它记录下来方便以后查阅.直接上代码: 界面调用  代码如下 复制代码 <script type="text/javascript"> function aaa(){  var student_panel = new WX.student.AddStudent({   //传入回调函数,直接显示.   callback_

python进阶教程之模块(module)介绍_python

我们之前看到了函数和对象.从本质上来说,它们都是为了更好的组织已经有的程序,以方便重复利用. 模块(module)也是为了同样的目的.在Python中,一个.py文件就构成一个模块.通过模块,你可以调用其它文件中的程序. 引入模块 我们先写一个first.py文件,内容如下: 复制代码 代码如下: def laugh():     print 'HaHaHaHa' 再写一个second.py,并引入first中的程序: 复制代码 代码如下: import first for i in range

Lua中访问table里函数的方法示例_Lua

看例子代码: 复制代码 代码如下: do  table_ = {   a = 1,   foo = function(i)      return i     end  }  print(table_.foo(1)) end

Lua中的捕获机制和转换技巧介绍_Lua

捕获 捕获是这样一种机制:可以使用模式串的一部分匹配目标串的一部分.将你想捕获的模式用圆括号括起来,就指定了一个捕获. 在string.find使用捕获的时候,函数会返回捕获的值作为额外的结果.这常被用来将一个目标串拆分成多个: 复制代码 代码如下: pair = "name = Anna" _, _, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)") print(key, value)    --> na

Lua的编译、执行和调试技术介绍_Lua

dofile读入文件编译并执行,真正完成功能的函数是loadfile;与dofile不同,loadfile仅仅是编译代码成中间码,并且把编译后的chunk作为函数返回.如果发生错误,返回nil和错误信息.我们可以这么定义dofile: 复制代码 代码如下: function dofile(filename)      local f = assert(loadfile(filename))      return f() end 如果你只调用一次,可以使用dofile(filename),如果是

我们也说说Android.mk(2) - 函数进阶教程 - 分支、循环、子程序

我们也说说Android.mk(2) 函数进阶教程 - 分支.循环.子程序 按照面向过程程序设计的标准流程,我们讲完了顺序结构,就要讲分支.循环和子程序.下面我们就开始讲用于分支.循环和子程序调用功能的函数. 分支函数 要走分支,一定是要有条件要判断. 在Makefile里,最主要的判断就是看字符串能不能找到了. 通过findstring函数来进行这个判断,然后用if函数使用findstring函数的结果. 例: .PHONY : all5 bootoatfile := out/target/p

窥探Swift之函数与闭包的应用实例

今天的博客算是比较基础的,还是那句话,基础这东西在什么时候都是最重要的.说到函数,只要是写过程序就肯定知道函数是怎么回事,今天就来讨论一下Swift中的函数的特性以及Swift中的闭包.今天的一些小实例中回类比一下Objective-C中的函数的写法等等.Swift中的函数还是有许多好用的特性的,比如输入参数,使用元组返回多个值, 定义形参名,设定默认参数以及可变参数等等一些好用的特性.而在Swift中的闭包就是Objective-C中的Block, 除了语法不通外,两者的用法是一样的.废话少说

php 获取文件大小函数与实例教程

php 获取文件大小函数与实例教程 <?php function getFileSize($url){ $url = parse_url($url); if($fp = @fsockopen($url['host'],empty($url['port'])?80:$url['port'],$error)){ fputs($fp,"GET ".(empty($url['path'])?'/':$url['path'])." HTTP/1.1rn"); fputs