引述
LUA中的表就是一个对象:
- 表与对象一样可以拥有状态
- 表与对象一样都拥有一个与值无关的标识:self
- 两个具有相同值的对象(表)是两个不同的对象,而一个对象可以拥有多个不同的值
- 表与对象一样,拥有与创建着和被创建位置无关的生命周期
对象有自己的操作,表也有,例:
People = {money = 0}
function People.earn_money(money)
People.money = People.money + money
end
上面的代码创建了一个新函数,并将该函数存入People的earn_money字段,然后就可以进行如下调用:
People.earn_money(100)
接下来换一种方法表示这个函数:
function People.earn_money(self, money)
self.money = self.money + money
end
上述方法通过对操作的接受者进行操作,替代了原来的直接调用全局名称People
通过使用参数self,可以对多个对象调用相同的方法:
People = {money = 0}
function People.earn_money(self, money)
self.money = self.money + money
end
p1 = {money = 0, earn_money = People.earn_money}
p2 = {money = 0, earn_money = People.earn_money}
p1.earn_money(p1, 100)
p2.earn_money(p2, 200)
print(p1.money) -- 100
print(p2.money) -- 200
LUA中有一种语法糖,使用冒号操作符隐藏传入的self参数,我们可以将上述函数重写为:
function People:earn_money(money)
self.money = self.money + money
end
可以使用冒号来定义函数,同样也可以使用冒号来调用方法,所以可以将上述例子重写为:
People = {money = 0}
function People:earn_money(money)
self.money = self.money + money
end
p1 = {money = 0, earn_money = People.earn_money}
p2 = {money = 0, earn_money = People.earn_money}
p1:earn_money(100)
p2:earn_money(200)
print(p1.money) -- 100
print(p2.money) -- 200
类(Class)
LUA语言中本没有类的概念,虽然元表的概念在某种程度上与类的概念相似,但是把原表当作类使用在后续会比较麻烦。相反,我们可以参考基于原型的语言中的一些做法来在LUA语言中模拟类。在这些语言中,对象不属于类,每个对象可以有一个原型。原型也是一种普通的对象,当对象遇到遇到一个未知操作时,会首先在原型中查找。要在这种语言中表示一个类,我们只需要创建一个专门被用作其他对象(类的实例)的原型对象即可。类和原型都是一种组织多个对象间共享行为的方式。
在LUA语言中,如果有两个对象A和B,要让B成为A的一个原型,只需要:
setmetatable(A, {__index = B})
使用上述的People的例子,我们可以使用__index方法让这些新对象从People中继承earn_money操作:
People = {money = 0}
function People:earn_money(money)
self.money = self.money + money
end
function People.new(o)
o = o or {}
setmetatable(o, {__index = People})
return o
end
p1 = People.new{money = 0} -- 创建p1对象
p1:earn_money(100) -- getmetatable(p1).__index.earn_money(p1, 100)
print(p1.money) -- 100
在上述例子中,我们让p1的元表设置为{__index = People},这样当p1对象中找不到earn_money方法时,就会去元表中的__index中搜索,此时实际上发生了如下调用:
getmetatable(p1).__index.earn_money(p1, 100)
再使用LUA提供的语法糖(冒号方法),可以将上述new函数写成如下:
function People:new(o)
o = o or {}
self.__index = self
setmetatable(o, self)
return o
end
继续上面的例子,p1调用earn_money方法的时候会按照如下格式调用:
p1:earn_money(100)
实质上调用方式是:
p1.earn_money(p1, 100)
那么就是执行了:
p1.money = p1.money + 100
等号后面p1.money是继承父类的0,赋值完成之后,p1就拥有了money这个属性,并且值为100,此后再调用此属性的时候就不会再涉及元方法了。
网友评论