lua学习:lua中“类”的实现

转载 2016年05月31日 12:46:06

在之前的面试遇到考用lua实现类的题目。现在就补补这块知识点。

我们都知道Lua中的table是一个对象。拥有状态,拥有self,拥有独立于创建者和创建地的生命周期。

一个类就是一个创建对象的模具。Lua没有类的概念,但我们可以模拟类。

我们首先看看元表和元方法。这两个东西和我们模拟类有关。

Lua 本身是函数式的语言,但借助 metatable (元表)这个强大的工具,Lua 实现操作符重载易如反掌。就像两个表相加,只要我们在元表中写上__add方法就可以实现了。

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. meta={  
  2.     __add=function(op1,op2)  
  3.         op = {}  
  4.         op.x = op1.x + op2.x  
  5.         op.y = op1.y + op2.y  
  6.         return op  
  7.     end  
  8. }  
  9. a={x=1,y=1}  
  10. setmetatable(a,meta)  
  11. b={x=3,y=4}  
  12. c = a + b  
  13. print(c.x, c.y) -- 输出 4,5 建立自己的类  

通过这个方法,我们可以定义“类”的构造函数,析构函数。

除了与操作符重载有关的元方法以外,要建立自己的类,我们不得不认识另外一个元方法,它就是大名鼎鼎的“__index”。当表格搜寻成员未果的时候,Lua 会触发它,__index 所指向的元方法,元方法所返回的结果就成为了搜寻结果。如果没有这个元方法,那么访问结果为nil。__index元方法还可以直接为一张表(细数起来,这可是张表中表中表了)。

我们就用《Lua程序设计第二版》书中的例子说说Lua有关继承的典型示例吧。

假设要创建一些描述窗口的table,每个table中必须描述一些窗口参数,例如位置、大小及主题颜色等。所有这些参数都有默认值,因此希望在创建窗口对象时可以仅指定那些不同于默认值的参数。我们让新窗口从一个原型窗口处继承所有不存在的字段。首先,声明一个原型和一个构造函数,构造函数创建新的窗口,并使它们共享一个元表:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Window = {} --创建一个名字空间  
  2. --使用默认值来创建一个原型  
  3. Window.prototype = {x=0,y=0,width=100,height=100}  
  4. Window.mt = {} --创建元表  
  5. --声明构造函数  
  6. function Window.new(o)  
  7.     setmetatable(o,Window.mt)  
  8.     return o  
  9. end  

现在,来定义__index元方法:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Window.mt.__index = function(table,key)  
  2.     return Window.prototype[key]  
  3. end  

在这段代码之后,创建一个新窗口,并查询一个它没有的字段:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. w = Window.new{x=10,y=20}  
  2. print(w.width) -->100  

若Lua检测到w中没有某字段,但在其元表中却有一个__index字段,那么Lua就会以w(table)和"width"(不存在的key)来调用这个__index元方法。随后元方法用这个key来索引原型table,并返回结果。

在Lua中,将__index元方法用于继承是很普遍的方法,因此Lua还提供了一种更便捷的方式来实现此功能。__index元方法不必一定是一个函数,它还可以是一个table。当它是一个函数时,Lua以table和不存在的key作为参数来调用该函数,这就如同上述内容。而当它是一个table时,Lua就以相同的方式来重新访问这个table。因此,前例中__index的声明可以写为:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Window.mt.__index = Window.prototype  

我们现在可以写一个简历的类了:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. A = {x=0,y=0}  
  2. --这句是重定义元表的索引,必须要有,  
  3. A.__index = A  
  4.   
  5. --模拟构造体,一般名称为new()  
  6. function A:new(x,y)  
  7.         local self = {}     
  8.         setmetatable(self, A)   --必须要有  
  9.         self.x = x     
  10.         self.y = y  
  11.         return self    
  12. end  
  13.   
  14. function A:test()  
  15.     print(self.x,self.y)  
  16. end  
  17.   
  18. objA = A:new(1,2)  
  19. objA:test()  
  20. print(objA.x,objA.y)  

那这个类怎样被继承?

假设有一个基类A:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. A = {}  
  2.   
  3. function A:new(o)  
  4.     o = o or {}  
  5.     setmetatable(o,self)  
  6.     self.__index = self  
  7.     return o  
  8. end  
  9.   
  10. function A:funName()  
  11.     print('A')  
  12. end  

若想从这个类派生出一个子类B,以使其能打印出类名。则先需要创建一个空的类,从基类继承所有的操作:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. B = A:new()  

直到现在,B还只是A的一个实例。如下所示:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. s = B:new()  

B从A中继承了new,就像继承其他方法一样。不过这次new在执行时,它的self参数表示为B。因此,s的元表为B,B中字段__index的值也是B。s继承自B,而B又继承自A。当B重写funName()函数:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. function B:funName()  
  2.     print('B')  
  3. end  

现在调用

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. s:funName()  

输出的是B。


参考:

《Lua程序设计第二版》

Lua的类实现继承、多态以及setmetatable方法:http://blog.csdn.net/ym012/article/details/7206968

lua,让人惊叹的艺术:http://bbs.uc.cn/thread-2663965-1-1.html

lua面向对象是怎么实现的:http://www.2cto.com/kf/201402/280177.html(这个没有用到metatable ,相当来说易懂点)

云风oo:http://blog.codingnow.com/cloud/LuaOO

Lua 中实现类

Lua中是没有类的概念的,但是程序猿说要面向对象,所以就有了。
  • cp790621656
  • cp790621656
  • 2015年11月03日 18:30
  • 1547

lua中面向对象(class)实现探索(一)

说明:本文亦作为内部教程出现在中山大学某实验师bian
  • mywcyfl
  • mywcyfl
  • 2014年07月11日 22:48
  • 5100

单例模式lua实现

优点 一、实例控制 单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 二、灵活性 因为类控制了实例化过程,所以类可以灵活更改实例化过程。 缺点 一、开...
  • a374826954
  • a374826954
  • 2013年11月14日 10:30
  • 8752

lua 类继承和实现

从代码上说明 Account={balance=0}; --新建了一个对像,他有一个属性balance function Account:new(o) --这里的 :new(o) 中的冒号...
  • ssihc0
  • ssihc0
  • 2012年07月12日 23:42
  • 9560

lua实现类与继承,多继承

--采用闭包方式实现类的概念-- --eg: 创建一个 Person类 local function Person() local tab = { high = 0, wight = 0, ...
  • u011210708
  • u011210708
  • 2016年12月12日 10:22
  • 736

lua中用table实现队列

当函数只有一个参数并且这个参数是字符串或者表构造的时候,()是可选的。 print “Hello World” print(“Hello World”) f{x=10, y=20} f({x=...
  • qq_16209077
  • qq_16209077
  • 2016年10月26日 00:10
  • 15243

Lua类函数的几种构造方法

一、使用module函数在Lua的开头文件中声明:module("ClassA", package.seeall)后面声明函数:function test()end则在其他Lua文件中只要requir...
  • asmcvc
  • asmcvc
  • 2017年06月02日 18:12
  • 821

Lua类继承的优雅实现方式

网上有一些Lua类继承的示例,但是无法实现方法覆盖,同时能调用已经被覆盖的父类的方法。parent.lualocal _M = {}function _M:new(name) return s...
  • jie12310
  • jie12310
  • 2016年07月15日 21:41
  • 1648

LUA学习路线汇总

语法   Lua程序设计Programming in Lua   果冻想-Lua 语法入门 源码   the implementation of lua 50 英文原版 中文翻译   Lua源码鉴...
  • lodypig
  • lodypig
  • 2016年12月09日 21:08
  • 1191

如何学习Lua编程

转自:http://lua.javaeye.com/blog/456531 最近迷上了使用Lua写一些方便的小程序,也看了一些关于lua的文档。发现不少人经常问一些很常见的问题,感觉好像还没有找到学习...
  • jphaoren
  • jphaoren
  • 2010年06月16日 02:04
  • 1618
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:lua学习:lua中“类”的实现
举报原因:
原因补充:

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