其實(shí) Lua 中的 table 是一種對(duì)象,因?yàn)樗鷮?duì)象一樣,有其自己的操作方法:
復(fù)制代碼 代碼如下:
Role = { hp = 100 }
function Role.addHp(hp)
Role.hp = Role.hp + hp
end
Role.addHp(50)
print(Role.hp)
上面代碼創(chuàng)建了一個(gè)名為 Role 對(duì)象,并有一個(gè) addHp 的方法,執(zhí)行 "Role.addHp" 便可調(diào)用 addHp 方法。
不過(guò)上面對(duì)象 Role 是以全局變量的方式創(chuàng)建,會(huì)有一種“全局污染”的威脅,即變量 Role 在其他地方被重新賦值(例如被賦成 nil),對(duì)象里的屬性或方法可能會(huì)面臨被銷(xiāo)毀或不能正常工作的情況。
對(duì)于這種問(wèn)題,Lua 提供一種“接受者”的解決方法,即額外添加一個(gè)參數(shù) self 來(lái)表示對(duì)象本身:
復(fù)制代碼 代碼如下:
Role = { hp = 100 }
function Role.addHP(self, hp)
self.hp = self.hp + hp
end
r = Role
r.addHP(r, 50)
print(r.hp)
這樣就不怕對(duì)象 Role 被“全局污染”,因?yàn)闃?gòu)造了一個(gè)子對(duì)象 r,并以參數(shù)的方式傳入,以供其方法調(diào)用操作。
對(duì)于這種把對(duì)象本身以參數(shù)的方式傳入對(duì)象方法里的寫(xiě)法,Lua 提供了一種更優(yōu)雅的寫(xiě)法,把點(diǎn)號(hào)(.)替換為冒號(hào)(:),這樣在方法定義或調(diào)用時(shí),便可隱藏 self 參數(shù)。修改如下:
復(fù)制代碼 代碼如下:
Role = { hp = 100 }
function Role:addHp(hp)
self.hp = self.hp + hp
end
r = Role
r:addHp(50)
print(r.hp)
上面的 "r.addHp(50)" 的寫(xiě)法等價(jià)于 "r.addHp(r, 50)"
類(lèi)
Lua 沒(méi)有類(lèi)的概念,不過(guò)可以通過(guò)元表(metatable)來(lái)實(shí)現(xiàn)與原型 prototype 類(lèi)似的功能,而 prototype 與類(lèi)的工作機(jī)制一樣,都是定義了特定對(duì)象行為。Lua 里的原型特性主要使用元表的 __index 事件來(lái)實(shí)現(xiàn),這樣當(dāng)調(diào)用對(duì)象沒(méi)定義的方法時(shí),會(huì)向其元表的 __index 鍵(事件)查找。例如有 a 和 b 兩個(gè)對(duì)象,想讓 b 作為 a 的原型 prototype,只需要把 b 設(shè)置為 a 元表的 __index 值就行:
復(fù)制代碼 代碼如下:
setmetatable(a, {__index = b})
這樣,當(dāng)對(duì)象 a 調(diào)用任何不存在的成員都會(huì)到對(duì)象 b 中查找,a 可以擁有或調(diào)用 b 的屬性或方法,從某種意義上看,b 可以看作是一個(gè)類(lèi),a 是 b 的對(duì)象。
對(duì)于上面 Role 的例子,對(duì)象的創(chuàng)建可以用 __index 元方法來(lái)改寫(xiě),這樣新創(chuàng)建的對(duì)象就擁有和 Role 一樣的屬性和方法。
復(fù)制代碼 代碼如下:
function Role:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
當(dāng)執(zhí)行 "r = Role:new() " 創(chuàng)建一個(gè)對(duì)象時(shí),r 將 Role 設(shè)置為自己的元表,那么調(diào)用 "r:addHp(50)" 的時(shí)候,會(huì)在 r 里查找 addHp 方法,如果沒(méi)有找到,則會(huì)進(jìn)一步搜索其元表的 __index,因此等價(jià)于:
復(fù)制代碼 代碼如下:
getmetatable(r).__index.addHp(r, 50)
從上面的 Role:new 方法可以知道,Role 的 __index 在創(chuàng)建時(shí)被指定為 self,因此其實(shí)就是執(zhí)行:
復(fù)制代碼 代碼如下:
Role.addHp(R, 50)
完整的類(lèi)例子:
復(fù)制代碼 代碼如下:
Role = { hp = 100 }
function Role:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Role:addHp(hp)
self.hp = self.hp + hp
end
r = Role:new()
r:addHp(50)
print(r.hp)
繼承
Lua 里繼承機(jī)制還是像實(shí)現(xiàn)類(lèi)那樣實(shí)現(xiàn)。
假如打算從類(lèi) Role 派生出一個(gè)子類(lèi) Priest,它有一個(gè)魔法屬性值 mp,那么可以先從類(lèi) Role 構(gòu)造一個(gè) Priest,繼承類(lèi) Role 的所有屬性和方法:
復(fù)制代碼 代碼如下:
Priest = Role:new()
雖然 Priest 是 Role 的一個(gè)實(shí)例,不過(guò)它具有類(lèi) Role 的所有屬性和方法,其實(shí)也可以把它看做是從類(lèi) Role 派生出來(lái)的類(lèi),因此可以從類(lèi) Priest 繼續(xù) new 一個(gè)對(duì)象出來(lái):
復(fù)制代碼 代碼如下:
p = Priest:new({ mp = 100 })
上面實(shí)例 p 除了多出一個(gè)魔法屬性值 mp 外,還繼承類(lèi) Role 的所有屬性和方法,當(dāng)調(diào)用 "p.addHp" 方法時(shí),Lua 在 p 中找不到 addHp 方法,會(huì)到 Priest 中找,在 Priest 中找不到,會(huì)到 Role 中找。
因此,想重定義從父類(lèi) Role 繼承來(lái)的方法,在類(lèi) Priest 上定義即可。假如想重定義 addHp 方法:每次加血都要先判斷魔法值夠不夠,如果夠,則加血,并扣除一定的魔法值。修改如下:
復(fù)制代碼 代碼如下:
function Priest:addHp(hp)
if self.mp >= 20 then
self.mp = self.mp - 20
self.hp = self.hp + hp
end
end
這樣,當(dāng)調(diào)用 "p:addHp" 時(shí),Lua 會(huì)優(yōu)化取類(lèi) Priest 定義的 addHp 方法。
您可能感興趣的文章:- Lua中的string庫(kù)(字符串函數(shù)庫(kù))總結(jié)
- Lua中的函數(shù)(function)、可變參數(shù)、局部函數(shù)、尾遞歸優(yōu)化等實(shí)例講解
- Lua中的一些常用函數(shù)庫(kù)實(shí)例講解
- Lua中的模塊與module函數(shù)詳解
- Lua中的函數(shù)知識(shí)總結(jié)
- Lua字符串庫(kù)中的幾個(gè)重點(diǎn)函數(shù)介紹
- Lua的table庫(kù)函數(shù)insert、remove、concat、sort詳細(xì)介紹
- Lua中的常用函數(shù)庫(kù)匯總
- Lua中的面向?qū)ο缶幊淘斀?/li>
- Lua面向?qū)ο笾?lèi)和繼承
- Lua面向?qū)ο笾嘀乩^承、私密性詳解
- Lua中函數(shù)與面向?qū)ο缶幊痰幕A(chǔ)知識(shí)整理