元表
首先lua中的number類型是可以執(zhí)行一些操作的霜浴,比如
1 + 1 //2
1 - 1 //0
如果我們定義兩個復(fù)數(shù)如下昨登,希望能實現(xiàn)其的加法
local a = {1, 2}
local b = {3, 4}
// 相加我們希望得到 {4, 6}
如果我們直接相加這兩個變量辜腺,lua解釋器會告訴我們有錯誤默勾。
這個時候我們就可以通過元表的方式來達到我們期望的結(jié)果碉渡,元表可以理解為一個元操作或者行為的集合∧赴可以通過 setmetatable
設(shè)置table
的元表 getmetatable
獲取任意變量的元表滞诺。一個新的table創(chuàng)建時元表為空形导。
表達式a+b,在Lua中是按照以下步驟進行的
- 先判斷a和b兩者之一是否有元表
- 檢查該元表中是否有一個叫__add的字段铭段;如果找到了該字段骤宣,就調(diào)用該字段對應(yīng)的值,這個值對應(yīng)的是一個方法序愚;
在Lua中,每個值都有一個元表等限,table和userdata類型的每個變量都可以有各自獨立的元表爸吮,而其他類型的值則共享其類型所屬的單一元表。
local m = {
__add = function (a, b)
return {a[1] + b[1], a[2] + b[2]}
end
}
local a = setmetatable({1,2}, m)
local b = setmetatable({3,4}, m)
// 這時a + b 就會得到結(jié)果 {4, 6}
除了加法望门,元表中還有其他的操作如下表
Mode | 描述 |
---|---|
__add | 加 |
__sub | 減 |
__mul | 乘 |
__div | 除 |
__mod | 取余 |
__unm | 取相反數(shù) |
__concat | 連接 |
__eq | 等于 |
__lt | 小于 |
__le | 小于等于 |
__call | 將table作為方法調(diào)用時會調(diào)用元表的__call |
__tostring | 將table作為string傳入時會調(diào)用元表的__tostring |
__index | 下面講 |
__newindex | 下面講 |
__index元方法
訪問一個table的字段時形娇,如果table有這個字段,直接返回對應(yīng)的值筹误;
當(dāng)table沒有這個字段桐早,就會去找table的元表的__index,沒有找到返回nil。
如果有的話分兩種情況厨剪,__index可以是方法也可以是一個table哄酝。
如果是一個方法,會將table和key傳入調(diào)用此方法祷膳,結(jié)果如下
local m = {
__index = function(table, key)
return key .. key
end
}
local t = {}
setmetatable(t, m)
// 這時 t.a == 'aa', t.abc == 'abcabc'
如果是一個table,就會去找這個table對應(yīng)的key,找到則返回陶衅,沒找到則會繼續(xù)找這個table的元表的__index,也就是說會一直向上尋找直晨。
local a = {}
local b = {a = 1}
local c = {b = 2}
setmetatable(a, {__index = b})
setmetatable(b, {__index = c})
// a.a == 1
// a.b == 2
__newindex元方法
這個方法是在更新table的key時調(diào)用搀军,也就是給table的key賦值時。主要的作用在于可以
local a = {}
setmetatable(a, {
__newindex = function(table, key, value)
print(key)
print(value)
end
})
a.a = 10
// 會打印出 a 10
面向?qū)ο?/h2>
有了上面元表的基礎(chǔ)勇皇,我們就可以實現(xiàn)lua的面向?qū)ο罅苏志洹N覀兌x一個table作為類,當(dāng)我們創(chuàng)建對象時敛摘,將這個類作為元方法中的__index,再使用lua中的self關(guān)鍵字
local People = {
name = ''
}
function People:say()
print(self.name)
end
function People:new(name)
local o = {name = name}
setmetatable(o, {__index = self})
return o
end
local xiaoming = People:new('xiaoming')
xiaoming:say() // 打印出 xiaoming
下面是繼承
local People = {
name = ''
}
function People:say()
print(self.name)
end
function People:new(name)
local o = {name = name}
setmetatable(o, {__index = self})
return o
end
local Teacher = {
}
function Teacher:say()
print('teacher ' .. self.name)
end
setmetatable(Teacher, {__index = People})
local xiaoming = Teacher:new('xiaoming')
xiaoming:say() // 打印出 teacher xiaoming
當(dāng)然门烂,實現(xiàn)類與對象和繼承的方式還有其他的很多種,上面只是示范其中的原理着撩。我們可以封裝一個 class 方法诅福,用來定義類并可以傳入父類,更方便地實現(xiàn)面向?qū)ο笸闲稹_@里就不詳述了氓润。直接搜索相關(guān)關(guān)鍵字就好。