類
在很多面向?qū)ο蟮恼Z言中有類(class)的概念,對(duì)象是類的實(shí)例。Lua 中不存在類的概念。Lua 就像 JavaScript 一樣是面向原型的語言(http://en.wikipedia.org/wiki/Prototype-based_programming),這類語言使用一個(gè)對(duì)象表示一個(gè)“類”,其他對(duì)象(此類的實(shí)例)使用此對(duì)象作為原型。我們有兩個(gè) table p 和 obj,將 p 設(shè)置為 obj 的原型(回顧:http://www.jfrwli.cn/article/57847.html):
setmetatable(obj, {__index = p})
obj 中不存在的操作會(huì)在 p 中查找。
看一個(gè)詳細(xì)的例子:
Account = {
-- 默認(rèn)的 balance 的值
balance = 0
}
function Account:new(o)
o = o or {}
-- 設(shè)置原型為 Account
setmetatable(o, self)
self.__index = self
return o
end
function Account:deposit(v)
self.balance = self.balance + v
end
function Account:withdraw(v)
if v > self.balance then
print('insufficient funds')
return
end
self.balance = self.balance - v
end
-- 構(gòu)建 Account 對(duì)象,初始 balance 為 100
local a1 = Account:new{balance = 100}
a1:deposit(100) --> balance == 200
a1:withdraw(100) --> balance == 100
-- 構(gòu)建 Account 對(duì)象,使用默認(rèn)的 balance
local a2 = Account:new()
a2:deposit(100) --> balance == 100
在方法定義時(shí)使用冒號(hào)能夠添加一個(gè)隱藏的參數(shù) self 給方法,在方法調(diào)用時(shí)使用冒號(hào)能夠?qū)⒄{(diào)用者作為一個(gè)額外的參數(shù)傳遞給此方法,例如:
-- 以下兩種寫法等價(jià)
function Account:deposit(v)
function Account.deposit(self, v)
-- 以下兩種寫法等價(jià)
a1:deposit(100)
a1.deposit(a1, 100)
self 為方法的調(diào)用者。
在 Account 這個(gè)例子中,一個(gè)小優(yōu)化是,我們沒有必要?jiǎng)?chuàng)建一個(gè)額外的 metatable,而直接使用 Account 作為 metatable。
繼承
我們通過一個(gè)例子來解釋 Lua 如何實(shí)現(xiàn)繼承。假定我們需要子類 SpecialAccount 繼承于 Account,SpecialAccount 是可以透支的。
首先構(gòu)造一個(gè)子類:
SpecialAccount = Account:new()
這里 SpecialAccount 擁有了(繼承了)Account 的 new 方法。那么我們就可以使用 SpecialAccount 構(gòu)建對(duì)象:
local sa = SpecialAccount:new{limit = 1000}
sa:withdraw(100)
這里通過 SpecialAccount:new 構(gòu)造了對(duì)象 sa,并且 sa 的 metatable 為 SpecialAccount。執(zhí)行 sa:withdraw(100),Lua 在 sa 中找不到 withdraw,就會(huì)在 SpecialAccount 中找,在 SpecialAccount 中也找不到 withdraw,然后在 Account 中找到 withdraw 并調(diào)用它。Account 中的 withdraw 顯然不是我們想要的,我們?cè)?SpecialAccount 中重新定義它:
function SpecialAccount:withdraw(v)
if v - self.balance >= self:getLimit() then
print('insufficient funds')
return
end
self.balance = self.balance - v
end
function SpecialAccount:getLimit()
return self.limit or 0
end
我們?cè)僬{(diào)用 sa:withdraw(100),Lua 先在 SpecialAccount 中找到 withdraw 并調(diào)用它。