Lua的面向对象
2017-01-07 15:56
260 查看
__index和__newindex
__index元方法用来对表访问,__newindex元方法用来对表更新 。当通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index键。如果__index指向一个表格,Lua会在表格中查找相应的键,如果__index指向一个函数,Lua会将以table和key作为参数调用该函数,并返回该函数的返回值。
访问表元素时的规则:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
3.判断元表有没有__index键,如果__index为nil,则返回nil;如果__index指向一个表,则重复1、2、3;如果__index指向一个函数,则返回该函数的返回值
更新表元素的规则:
1.如果table有该元素,直接为该元素更新值;
2.如果table无该元素,且table的元表为nil或元表不为nil但元表的__newindex为nil,则直接为table添加元素;
3.如果table无该元素,且存在元表,元表的__newindex不为nil,则通过__newindex来操作,具体是:如果__newindex指向一个表,重复上述步骤;如果__newindex指向一个函数,以table,key,value作为参数调用该函数。
基于对象
一个简单实例:Rectangle = {area = 0, length = 0, breadth = 0} function Rectangle:new (o,length,breadth) o = o or {} setmetatable(o, self) self.__index = self self.length = length or 0 self.breadth = breadth or 0 self.area = length*breadth return o end function Rectangle:printArea () print("矩形面积为",self.area) end myshape = Rectangle:new(nil,2,10) myshape:printArea()
这里的
:是一个语法糖,定义函数时,相当于把
:换成
.并将self作为第一个形参;调用函数时,相当于把
:换成
.并将调用函数的table作为第一个实参。
还原后的代码:
Rectangle = {area = 0, length = 0, breadth = 0} function Rectangle.new (self,o,length,breadth) o = o or {} setmetatable(o, self) self.__index = self self.length = length or 0 self.breadth = breadth or 0 self.area = length*breadth return o end function Rectangle.printArea (self) print("矩形面积为 ",self.area) end myshape = Rectangle.new(Rectangle,nil,2,10) myshape.printArea(myshape)
在myshape.printArea(myshape)中:
因为myshape里边没有printArea,去找元表Rectangle的__index,__index指向Rectangle,Rectangle里有printArea,所以就去调用Rectangle的printArea。在Rectangle的printArea里打印myshape.area,myshape里没有area,又去Rectangle的__index里找,找到并打印了出来。
但是在这里,数据不是保存在new出来的实例中的,而是保存在Rectangle中,这就像c++里类的静态成员变量和静态成员函数。比如这样用:
myshape1 = Rectangle:new(nil,2,5) myshape2 = Rectangle:new(nil,4,10) myshape1:printArea() myshape2:printArea()
打印出来的都是40。
我们换一种更好的方式:
Rectangle = {} Rectangle.__index = Rectangle function Rectangle.new (length,breadth) o = {} setmetatable(o, Rectangle) o.length = length or 0 o.breadth = breadth or 0 o.area = o.length*o.breadth return o end function Rectangle:printArea () print("矩形面积为",self.area) end myshape1 = Rectangle.new(2,10) myshape2 = Rectangle.new(4,10) myshape1:printArea() myshape2:printArea()
面向对象
通过__index实现继承的例子如下:Rectangle = {} Rectangle.__index = Rectangle function Rectangle.new(o, length, breadth) o = o or {} o.length = length or 0 o.breadth = breadth or 0 o.area = o.length * o.breadth setmetatable(o, Rectangle) return o end function Rectangle:getArea() return self.length * self.breadth end Cube = {} setmetatable(Cube, Rectangle) Cube.__index = Cube function Cube.new(o, length, breadth, height) o = o or {} Rectangle.new(o, length, breadth) o.height = height or 0 setmetatable(o, Cube) return o end function Cube:getVolume() return self.height*self:getArea() end r1 = Rectangle.new(nil,2,3) r2 = Rectangle.new(nil,3,4) print("r1的长是", r1.length, "宽是", r1.breadth) print("r1的面积是", r1:getArea()) print("r2的面积是", r2:getArea()) c1 = Cube.new(nil,4,5,6) c2 = Cube.new(nil,3,4,5) print("c1的面积是", c1:getArea()) print("c1的体积是", c1:getVolume()) print("c2的面积是", c2:getArea()) print("c2的体积是", c2:getVolume()) --[[输出是: r1的长是 2 宽是 3 r1的面积是 6 r2的面积是 12 c1的面积是 20 c1的体积是 120 c2的面积是 12 c2的体积是 60 ]]--
关键在于
setmetatable(Cube, Rectangle)和setmetatable(o, Cube),在c1中查找getVolume时,会在c1的元表Cube的__index指向的Cube中查找,正好找得到;在c1中查找getArea时,却找不到,就去Cube的元表Rectangle的__index指向的Rectangle中查找,也找到了。
虽然Lua也可以实现封装、抽象、派生,但也有点太麻烦了,设计简单,用起来就麻烦,OO也不是Lua擅长的,这种事情交给c++来做就好了。
比较像JavaScript的原型链,但简单多了。
相关文章推荐
- 【Lua】面向对象
- Lua面向对象代码(继承和多态)的读后感
- lua面向对象实现-类实例化对象、继承、多态、多继承、lua单例模式
- lua面向对象详解(2)
- lua面向对象思想
- lua面向对象实现-类实例化对象、继承、多态、多继承、lua单例模式
- lua中的面向对象模拟,类,继承,多态
- lua面向对象学习
- Lua编程示例(二):面向对象、metatable对表进行扩展
- lua面向对象学习随笔 --类与实例
- lua中的面向对象模拟,类,继承,多态
- Lua面向对象之类和继承浅析
- lua中的类功能(面向对象2)
- Cocos2d-x 脚本语言Lua中的面向对象
- Lua面向对象之二:类继承
- Lua学习笔记(五):面向对象的实现
- Lua程序设计(二)面向对象概念介绍
- Lua面向对象程序设计
- lua面向对象详解(3)
- lua 面向对象使用