一、前言
Lua 中一张表 table 就是一个对象(注意不是类,是对象)。他具有以下的特性:
- 表和对象都可以拥有状态
- 表和对象都拥有一个与其值无关的标识(self)
- 两个具有相同值的对象是两个不同的对象,而一个对象可以具有多个不同的值
- 表和对象一样,具有与创建者和被创建者位置无关的生命周期
二、类
1、 Lua 的类
Lua 并没有类这一概念,而是通过 “基于原型” 的方式进行组织,而原型其实也是一个实例对象。
换而言之,我们通过元表的方式,让 Lua 的实例对象在找不到对应的属性或方法时,从其元表的 __index
属性指定的表(即上面所说的原型,其实他也是实例对象)或方法中获取,而如果这里指定的表也没有对应的属性,则继续往该表(也就是原型)的元表继续查找,直到查找到或全部查找完还没有找到对应的属性或方法为止。
2、self 字段
在类中,this(在 Lua 中是 self) 很重要,因为他可以让不同实例调用同一方法不会有互相干扰。
举个例子
下面的例子中,withdraw
方法内部固定写了 Account
,所以只要将 Account
删除,则会有异常
local Account = {
balance = 0 }
function Account.withdraw(v)
Account.balance = Account.balance - v
end
Account.withdraw(100)
print(Account.balance) --> -100
local a, Account = Account, nil
a.withdraw(100) --> 这里会报错,因为 withdraw 内部使用了 Account ,而这个值已经被移除
所以这里如果有一个可以指向自身的指针就可以避免这一问题,则将 function Account.withdraw(v)
方法多加一个 self
参数,来决定函数内部的操作是针对哪个实例,变成为 function Account.withdraw(self, v)
,改变后的代码:
local Account = {
balance = 0 }
function Account.withdraw(self, v)
self.balance = self.balance - v
end
local a = Account
Account = nil
a.withdraw(a, 100)
print(a.balance)
但是这样的使用就会麻烦一些,每次使用都需要将自己传入,Lua 有一个语法糖,如果第一个参数是指向自身,则可以使用冒号(:
)进行调用。
同时也可以使用冒号(:
)进行定义方法,这样会自动在参数的最前面添加一个 self
的参数,方法内部就可以进行使用了,具体代码如下:
冒号定义的方法,也可以使用点方式调用,只是需要传入多一个参数指向自己
local Account = {
balance = 0 }
-- 使用 : 就相当于 function Account.withdraw(self, v)
function Account:withdraw(v)
self.balance = self.balance - v
end
local a &