三、lua面向对象
1、lua中的self
首先来看一个例子:
localAccount = {balance = 1000}
functionAccount.Withdraw(money)
Account.balance = Account.balance - money
end
localaa = Account;
aa.Withdraw(100)
print(aa.balance) --900
print(Account.balance) --900
Account= nil
--aa.Withdraw(100) --error : attempt to index upvalue 'Account'(a nil value)
当定义aa时,aa实际上是Account的一个“引用”,并不会实际的给aa分配该table的一个拷贝,类似于linux的硬链接或windows的内核对象,执行了Account= nil 之后,实际上这个table还在,只是Account对这个table的链接断裂,我们可以通过输出的两个值可以看出。
把Account 置为 nil 之后再调用Withdraw 函数,由于函数内使用了Account对象,所以会引起访问出错。
在看一个改进版本:
localAccount = {balance = 1000}
functionAccount.Withdraw(self,money)
self.balance = self.balance - money
end
localaa = Account
Account= nil
aa.Withdraw(aa, 100)
print(aa.balance)
aa:Withdraw(100)
print(aa.balance)
在这个版本中,调用Withdraw函数时,使用的是传入函数的self的balance值,这个self现在就是aa的“引用”了。Lua中提供了一个语法糖,使用冒号调用函数时,会把调用对象作为第一个参数传入函数。
请注意函数书写的三种方式:
(1) table中写函数,需要指定self参数:
local Account =
{
Withdraw = function(self , money)
end,
}
(2) 函数外部写函数,不指定self参数:
local Account = {}
functionAccount:Withdraw(money)
end
(3)函数外部写函数,指定self参数
local Account = {}
functionAccount.Withdraw(self , money)
end
虽然这里访问可以了,但是,这并不是面向对象,因为对aa中balance的修改实际上就是对Account中的balance修改。这里主要介绍self的用法,self其实与c++中的this指针有相同的作用。
2、继承
Lua中没有类的概念,对象是没有类型的,但是我们可以为一些对象构建相同的共有的行为,这就是原型,不过我们要模拟类也是可以的。由于原型与类在这里的作用相同,这里仍采用类的叫法。
要在lua中实现原型,可以用继承的方法,这里用到了setmetatable方法。
setmetatable(a, {__index = b})
这样就能让b作为a的原型,当要访问a中的某个字段或函数不存在时,就会在b中查找。
我们再来看一下另一个版本:
localAccountClass =
{
balance = 1000,
New = function(self , obj)
obj = obj or {}
setmetatable(obj , self)
self.__index = self
return obj