lua面向对象详解(2)

原创 2013年12月01日 23:24:49

前面讲了lua的table,讲得比较粗略,不过table将会在不断的运用中逐渐形成对它的认识,不必一开始就完全搞明白它的全部。从这里开始,将讲解lua的元表和元方法。

二、元表与元方法

我们知道c++ 中不能随便将两个对象相加,除非程序用户自己定义+操作符,指定两个对象相加时需要做的操作。lua也是一样,不能将两个table进行算术操作,但是有一种方法可以实现。

元表和元方法就是用来改变lua 中元素的特定行为的。

lua中对元表的操作有如下方法:

setmetatable(t, mt)   设置 t 的元表为mt ,也可以重新设定

getmetatable(t) 获取 t 的元表,如果t 没有元表则返回nil

这里虽然说是可以对lua中元素的元表进行操作,但实际上,lua代码中只可以对table的元表进行设置,如要设置其他类型值的元表,则必须通过C API来实现。

lua中的每个值都有一个元表,table和userdata可以各自有独立的元表,而其他类型的值则共享该类型所属的单一元表。新建的table不会自动创建元表。

任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元表,此元表表示他们的共同行为。一个table甚至可以作为自己的元表,用于描述特有的行为。

下面以一个元素集合为例,说明元表与元方法的应用:

localSet = {}

functionSet.New(obj)

   obj = obj or {}

   local tt = {}

   for k,v in ipairs(obj) do

      tt[v] = true

   end

   return tt

end

 

functionSet.Union(obja , objb)

   local obj = Set.New()

   for k in pairs(obja) do

      obj[k] = true

   end

   for k in pairs(objb) do

      obj[k] = true

   end

   return obj

end

 

functionSet.Intersesion(obja , objb)

   local obj = Set.New()

   for k,v in pairs(obja) do

      obj[k] = objb[k]

   end

   return obj

end

 

functionSet.Print(obj)

   io.write("{ ")

   for k in pairs(obj) do

      io.write(k.." ")

   end

   print("}")

end

这里用Set表示一个集合的属性tabel,定义了一个New方法,将传进来的一组值表示成一个集合,这里用一个数组来表示,以该元素值为键,值为true表示存在该元素。

obj= obj or {} 是lua中比较常见的一种写法,用于让元素obj有一个不为nil的值,当用户调用函数没有传table进来时,我们获取的obj就为nil值,这是对obj进行索引迭代就会出错。所以obj不为nil时则为本身,否则为一个空table。

Set的Union函数为处理两个集合的并集,分别将两个集合的元素都按规则填充到集合中即可。Intersection函数则处理两个集合的交集,这里用了一点下技巧,先遍历obja集合,每个k都是集合obja的元素,执行操作

obj[k]= objb[k]

则当k为objb中的元素时,objb[k]为true,所以obj[k]= true将元素k加入到结果集。

当k不为objb中的元素时,objb[k]为nil,所以执行obj[k]= nil不会将k加入到结果集。

localt1 = Set.New{1,2,3,4,5,6}

localt2 = Set.New{4,5,6,7,8,9}

Set.Print(t1)

Set.Print(t2)

输出为

{ 1 2 3 4 5 6 }

{ 4 5 6 7 8 9 }

那么,我们要实现用操作符来求两个集合的并集和交集该怎么办呢?

定义一个用作元表的table

localmet = {}

在Set的New函数中增加

setmetatable(tt, met)

将新建的集合table的元表设置为met,并设置元表两个元方法如下

met.__add= Set.Union

met.__mul= Set.Intersesion

这里用算术运算+计算并集,用*计算交集,样就可以了:

localt3 = t1 + t2

Set.Print(t3)

localt4 = t1 * t2

Set.Print(t4)

输出为

{1 2 3 4 5 6 7 8 9 }

{5 6 4 }

可以看到,t3确实是t1和t2的并集,t4确实是t1和t2的交集。

那么,table的元表又是如何运作的呢?

当lua解析器解析t1 + t2时,如果t1有元表,并且元表中有__add字段,则用t1元表的该元方法,而与t2的元表无关,只有当t1没有找到这种元方法是才会查找t2(注意如果t2的元表的__add元方法与t1不同的情形)。当t1和t2中都找不到__add元方法时,lua就会引发一个错误。

通过这个例子,我们想一下元表和元方法是什么?

我们可以把元表看成事本例中Set集合对象抽象出来的一个类对象(注意不是类,元表是table也是对象),这个对象定义了对于以它为元表的对象某些操作的行为(后面还会讲到,元对象提供的不单是方法,还有值)。

lua中只有对象,没有类,对象可以生成对象,再次强调这句话。

当对table进行索引某个方法或值时,lua首先会查找table本身是否有这样的方法或值,如果有则直接使用。否则,会查找该table是否存在元表,并在查找的元表中查找这样的方法或值。

lua中还定义了一些其他的具有通用操作符的元方法:

算术:__add(加法)、__sub(减法)、__mul(乘法)、__div(除法)、__unm(相反数)、__mod(取模)、__pow(乘幂)、__concat(字符串连接)

关系:__eq(等于)、__lt(小于)、__le(小于等于)

其他几个重要的元方法:

__tostring 可以定义将table表示为字符串的元方法

__metatable 调用setmetatable和getmetatable会用到元表的该元方法。如果手动设置元表的__metatable这个元方法的值,则会对table起到保护的作用,外部将不能访问该table的元方法,更不能调用setmetatable设置新元表。

localtt = {}

localmt = {}

mt.__metatable= "not your business"

setmetatable(tt, mt)

print(getmetatable(tt))

setmetatable(tt, {})

输出为

notyour business

lua:metatable2.lua:6: cannot change a protected metatable

__index做为lua中一个非常重要的元方法,它可以是一个函数也可以是一个table。当它为一个函数时,lua会以table和一个不存在不存在的key(存储的key则直接访问)来调用函数。如果为一个table,lua就以相同的方式来重新访问这个table。什么意思呢?来看下面的一个例子:

localwindow = {}

window.prototype= {x=10,y=20,width=10,height=10}

window.mt= {}

window.mt.__index= function(tbl , key)

   return window.prototype[key]

end

functionwindow.New(obj)

   obj = obj or {}

   setmetatable(obj , window.mt)

   return obj

end

localtb = window.New{x=20,y=30}

print(tb.x)

print(tb.width)

window表将一些属性存储在prototype中,还有一个作为元表的mt。当调用New函数生成对象tb时,设置了tb的元表为mt。当对tb索引x时,首先查找tb本身是否存在x键,发现存在则直接访问。索引width时,tb没有,lua发现它有元表,就跳转到表mt中,要访问mt必须找到__index元方法,发现是一个函数,则将tb和width作为参数传入调用。

那__index为table时又是什么情况呢,我们来做一个实验:

localwindow = {}

window.prototype= {x=10,y=20,width=20,height=20}

window.mt= {}

functionwindow.New(obj)

   obj = obj or {}

   setmetatable(obj , window.mt)

   return obj

end

localt = window.New{x=20,y=30}

print(t.width)

这里会输出什么呢?结果是nil。对t索引width时虽然会跳转到元表window.mt上,但是lua并不知如何处理元表window.mt(缺少__index元方法)。

当我们在window.mt = {}之后加上一行:

window.mt.__index= window.prototype

输出就是20了。

也就是说,元方法__index是告诉lua对元表应该如果访问或操作。前面的例子将mt的__index元方法指向一个函数,则lua会调用这个函数。这里将mt的__index指向一个table,则lua就会去访问这个table。

当然,这种访问还会引起其他的一下操作,我们将在面向对象的时候将到。


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

cocos2dx-lua中实现面向对象的封装继承

class函数是在"cocos2d-x-3.2/cocos/scripting/lua-bindings/script/extern.lua"中定义的。 -- Cre...

【quick-cocos2d-x】Lua 面向对象(OOP)编程与元表元方法

面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。 早期的计算机编程是基于面向过程的方法,通过设计一个算法就可以解决当时的问题。随着计算机技术的不断提高,计算机被用于...

Cocos2d-x 脚本语言Lua中的面向对象

面向对象不是针对某一门语言,而是一种思想,在面向过程的语言也可以使用面向对象的思想来进行编程。在Lua中,并没有面向对象的概念存在,没有类的定义和子类的定义,但同样在Lua中可以利用面向对象的思想来实...

cocos2d-x 平时例子(3)和lua写成面向对象

1.csloader 2.裁剪node 3.batchNode 4.lua面向对象小部分

lua面向对象详解(3)

三、lua面向对象 1、lua中的self 首先来看一个例子: localAccount = {balance = 1000} functionAccount.Withdraw(money)    A...

lua面向对象详解(1)

项目组有个很好的习惯,每个礼拜都开展技术交流活动,要求由其中一个同事作为主讲人,以该主讲人所擅长的技术方面为主题,进行交流。收到这个任务已经月余,但最近实在太忙,只得趁周末准备一下。学习lua已经是很...

Lua面向对象详解

简单说说Lua中的面向对象,Lua中的table就是一种对象,看以下一段简单的代码: 复制代码代码如下: local tb1 = {a = 1, b = 2} local tb2 = {a = 1, ...

Lua面向对象封装 链接库

  • 2012-10-18 14:12
  • 1.20MB
  • 下载

Lua支持面向对象代码

cocos2d-Lua02Lua面向对象

1 Lua中的面向对象 1.1 问题 lua不是一个面向对象的语言,但是他又有面向对象的思想。lua中的面向对象是伪面向对象,伪面向对象就要用到table实现。 由table模拟了一个面向对象的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)