Lua的面向对象

table元素访问和更新三大法则

__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作为参数调用该函数。

第三法则:语法糖“:”

-- 定义函数时,相当于把:换成.并将self作为第一个形参;
-- 调用函数时,相当于把:换成.并将调用函数的table作为第一个实参。
t={}
function t:f()
    print(self)
end
t:f()

基于对象

一个简单实例:

Rectangle = {area = 0, length = 0, breadth = 0}

function Rectangle:new (o,length,breadth)
    local o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.length = length or 0
    self.breadth = breadth or 0
    self.area = self.length*self.breadth
    return o
end

function Rectangle:printArea ()
    print("矩形面积为", self.area)
end

myshape = Rectangle:new(nil,2,10)
myshape:printArea()

在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)
    local 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(length, breadth)
    local o = {}
    o.length = length or 0
    o.breadth = breadth or 0
    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(length, breadth, height)
    local o = Rectangle.new(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(2,3)
r2 = Rectangle.new(3,4)
print("r1的长是", r1.length, "宽是", r1.breadth)
print("r1的面积是", r1:getArea())
print("r2的面积是", r2:getArea())

c1 = Cube.new(4,5,6)
c2 = Cube.new(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中查找,就找到了。

summary

虽然Lua也可以模拟实现封装、抽象、派生,但也有点太麻烦了,特意的OO可能反而得不偿失,要充分利用Lua本身的机制,灵活应用,再说OO应该交给宿主语言C++去做。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值