Lua 极简入门指南(七):面向对象编程
类
在很多面向对象的语言中有类(class)的概念,对象是类的实例。Lua中不存在类的概念。Lua就像JavaScript一样是面向原型的语言(http://en.wikipedia.org/wiki/Prototype-based_programming),这类语言使用一个对象表示一个“类”,其他对象(此类的实例)使用此对象作为原型。我们有两个tablep和obj,将p设置为obj的原型(回顾:https://www.nhooo.com/article/56690.htm):
setmetatable(obj,{__index=p})
obj中不存在的操作会在p中查找。
看一个详细的例子:
Account={ --默认的balance的值 balance=0 } functionAccount:new(o) o=oor{} --设置原型为Account setmetatable(o,self) self.__index=self returno end functionAccount:deposit(v) self.balance=self.balance+v end functionAccount:withdraw(v) ifv>self.balancethen print('insufficientfunds') return end self.balance=self.balance-v end --构建Account对象,初始balance为100 locala1=Account:new{balance=100} a1:deposit(100) -->balance==200 a1:withdraw(100) -->balance==100 --构建Account对象,使用默认的balance locala2=Account:new() a2:deposit(100) -->balance==100
在方法定义时使用冒号能够添加一个隐藏的参数self给方法,在方法调用时使用冒号能够将调用者作为一个额外的参数传递给此方法,例如:
--以下两种写法等价 functionAccount:deposit(v) functionAccount.deposit(self,v) --以下两种写法等价 a1:deposit(100) a1.deposit(a1,100)
self为方法的调用者。
在Account这个例子中,一个小优化是,我们没有必要创建一个额外的metatable,而直接使用Account作为metatable。
继承
我们通过一个例子来解释Lua如何实现继承。假定我们需要子类SpecialAccount继承于Account,SpecialAccount是可以透支的。
首先构造一个子类:
SpecialAccount=Account:new()
这里SpecialAccount拥有了(继承了)Account的new方法。那么我们就可以使用SpecialAccount构建对象:
localsa=SpecialAccount:new{limit=1000} sa:withdraw(100)
这里通过SpecialAccount:new构造了对象sa,并且sa的metatable为SpecialAccount。执行sa:withdraw(100),Lua在sa中找不到withdraw,就会在SpecialAccount中找,在SpecialAccount中也找不到withdraw,然后在Account中找到withdraw并调用它。Account中的withdraw显然不是我们想要的,我们在SpecialAccount中重新定义它:
functionSpecialAccount:withdraw(v) ifv-self.balance>=self:getLimit()then print('insufficientfunds') return end self.balance=self.balance-v end functionSpecialAccount:getLimit() returnself.limitor0 end
我们再调用sa:withdraw(100),Lua先在SpecialAccount中找到withdraw并调用它。