local CPU = { name = 'CPU', cost = 400 } local Monitor = { name = 'bird', cost = 200 } local Memory = { name = 'memory', cost = 100 } local Computer = { description = "this is a computer", cpu = CPU, monitor = Monitor, memory = Memory } function Computer.getDescription() return Computer.description end print(Computer.getDescription()) >
Lua的“面向对象”,实质上是利用表和元表制造的一层层“嵌套关系”。c1.description = 'this is c1'这行函数,本质上没有改变self的值,而是在c1对象中增加了description这一属性,因为在表中已经找到了,所以就不会访问元表中的description属性,造成‘改写’这现象。而如果访问的是cpu这个属性,因为c1中找不到,会访问元表,然后直到找到为止。如果访问gpu这个不存在的属性,会一直找下去,直到元方法__index为nil时退出。 下面的代码应该可以验证这一猜想。
1 2 3 4 5 6 7 8 9 10 11 12
c1 = Computer:new() print('before init description') for k, v in pairs(c1) do print(k, v) end print(c1.description) c1.description = 'this is c1' print('after init description') for k, v in pairs(c1) do print(k, v) end print(c1.description)
输出:在c1.description = 'this is c1'前key-value是没有任何输出的,说明c1没有这些东西(不包括元表的部分),但是又确确实实能输出(因为找不到就会访问元表)。
1 2 3 4 5
before init description this is a computer after init description description this is c1 this is c1
上面是无参的构造函数,如果是有参的,需要在构造函数中同时改变self中的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
function Computer:new(description) local o = {} setmetatable(o, self) self.__index = self self.description = description return o end
c1 = Computer:new('init description') print('c1 before', c1.description) --c1 before init description c1.description = 'this is c1' print('c1 after', c1.description) --c1 after this is c1 c2 = Computer:new() print('c2', c2.description) --c2 nil
local Shape = {} --定义基类 Shape.area = 0 --基类的成员area function Shape:new() local s = {} setmetatable(s, self) self.__index = self return s end
function Shape:getArea() --父类方法,可见子类也能访问 return self.area end
local Square = Shape:new() --关键语句,Square继承Shape function Square:new(side) --Square的构造函数 local s = {} setmetatable(s, self) self.__index = self --关键语句,元方法__index为空时候不会向元表查找area值 s.side = side or 0 --Square自身定义了成员变量side self.area = side * side --改变基类的area的值 return s end
local square = Square:new(10) print('square side', square.side) --square side 10 print('square area', square:getArea()) --square area 100