研究了八百年了
万恶之源: Metatable
Lua中table可以设置一个__metatable,这个__metatable里面会装一些有用的东西,比如当访问table中不存在的键时,姐十七号会在table.__metatable.__index中寻找相应的键(如果__index存在的话),并返回这个键的值。
写一个类
Lua的table可以封装对象的属性,往table里面塞function可以作为对象的方法。因此Lua中的table就可以作为一个对象来看待,我们只需要整一个大批量生成对象的function就行了。
-- 第一种方法: 直接在table中写匿名函数
MyClassA = {
new = function(self, o, my_value)
-- 有关实例化的内容
o = o or {}
setmetatable(o, self)
self.__index = self
-- 有关对象的内容(在new里接收的参数的处理)
self.my_value = my_value or 0
return o
end
}
-- 第二种方法: 在table外写函数
MyClassB = {}
function MyClassB:new(o, my_value)
-- 有关实例化的内容
o = o or {}
setmetatable(o, self)
self.__index = self
-- 有关对象的内容(在new里接收的参数的处理)
self.my_value = my_value or 0
return o
end
a = MyClassA:new(nil, 10)
b = MyClassB:new(nil, 20)
一些说明:
-
Lua中调用函数有两种方式: . 和 : 。’ . ‘ 表示正常调用,’ : ‘ 表示传入一个self的值。
A中写new时是直接用匿名函数的,所以跳过了选择 . 和 : 的过程; B中写new时是在外部用 ‘ : ‘ 写的,所以参数里没有self。如果这里用 ‘ . ‘ 写,那参数第一个就要写self了。 -
Lua中
a = a or 0
表示如果a的值为nil(即不存在)时,将a赋值为0,用这个可以设置变量的初始值。 -
有关实例化的三行内容:
o = o or {}
: 套话,其实就是o = {}
,因为o就是对象的初始值(是个table);setmetatable(o, self)
: 将MyClass设为实例化对象的元表;self.__index = self
: 将self的__index设为本身。 以及最后的return o
,总结起来就是,MyClass成了实例化对象的元表的__index,也就是说,我们的对象其实是那个o,也就是{},而它的类的信息在它的metatable的__index中,我们实际上是从这里找出了attribute和function。
用metatable生成类的实例
用相似的方法,我们可以做出一个仿真的 继承。
MyClassA = {
new = function(self, o, my_value)
-- 有关实例化的内容
o = o or {}
setmetatable(o, self)
self.__index = self
-- 有关对象的内容(在new里接收的参数的处理)
self.my_value = my_value or 0
return o
end
}
ChildClassA = MyClassA:new() -- 这时MyClassA已经成了ChildClassA的metatable的__index了
function ChildClassA:greet()
print('Hello! I am ' .. self.my_value)
end
cca = ChildClassA:new(nil, 114)
cca:greet()
我们新写的这个greet
函数在ChildClassA里,对MyClassA没有影响,而ChildClassA的new方法与MyClassA一样,也就是 继承。
End.