W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在 Lua 5.1 語(yǔ)言中,元表 (metatable) 的表現(xiàn)行為類(lèi)似于 C++ 語(yǔ)言中的操作符重載,例如我們可以重載 "__add" 元方法 (metamethod),來(lái)計(jì)算兩個(gè) Lua 數(shù)組的并集;或者重載 "__index" 方法,來(lái)定義我們自己的 Hash 函數(shù)。Lua 提供了兩個(gè)十分重要的用來(lái)處理元表的方法,如下:
設(shè)置元表的方法很簡(jiǎn)單,如下:
local mytable = {}
local mymetatable = {}
setmetatable(mytable, mymetatable)
上面的代碼可以簡(jiǎn)寫(xiě)成如下的一行代碼:
local mytable = setmetatable({}, {})
通過(guò)重載 "__add" 元方法來(lái)計(jì)算集合的并集實(shí)例:
local set1 = {10, 20, 30} -- 集合
local set2 = {20, 40, 50} -- 集合
-- 將用于重載__add的函數(shù),注意第一個(gè)參數(shù)是self
local union = function (self, another)
local set = {}
local result = {}
-- 利用數(shù)組來(lái)確保集合的互異性
for i, j in pairs(self) do set[j] = true end
for i, j in pairs(another) do set[j] = true end
-- 加入結(jié)果集合
for i, j in pairs(set) do table.insert(result, i) end
return result
end
setmetatable(set1, {__add = union}) -- 重載 set1 表的 __add 元方法
local set3 = set1 + set2
for _, j in pairs(set3) do
io.write(j.." ") -->output:30 50 20 40 10
end
除了加法可以被重載之外,Lua 提供的所有操作符都可以被重載:
元方法 | 含義 |
---|---|
"__add" | + 操作 |
"__sub" | - 操作 其行為類(lèi)似于 "add" 操作 |
"__mul" | * 操作 其行為類(lèi)似于 "add" 操作 |
"__div" | / 操作 其行為類(lèi)似于 "add" 操作 |
"__mod" | % 操作 其行為類(lèi)似于 "add" 操作 |
"__pow" | ^ (冪)操作 其行為類(lèi)似于 "add" 操作 |
"__unm" | 一元 - 操作 |
"__concat" | .. (字符串連接)操作 |
"__len" | # 操作 |
"__eq" | == 操作 函數(shù) getcomphandler 定義了 Lua 怎樣選擇一個(gè)處理器來(lái)作比較操作 僅在兩個(gè)對(duì)象類(lèi)型相同且有對(duì)應(yīng)操作相同的元方法時(shí)才起效 |
"__lt" | < 操作 |
"__le" | <= 操作 |
除了操作符之外,如下元方法也可以被重載,下面會(huì)依次解釋使用方法:
元方法 | 含義 |
---|---|
"__index" | 取下標(biāo)操作用于訪問(wèn) table[key] |
"__newindex" | 賦值給指定下標(biāo) table[key] = value |
"__tostring" | 轉(zhuǎn)換成字符串 |
"__call" | 當(dāng) Lua 調(diào)用一個(gè)值時(shí)調(diào)用 |
"__mode" | 用于弱表(week table) |
"__metatable" | 用于保護(hù)metatable不被訪問(wèn) |
下面的例子中,我們實(shí)現(xiàn)了在表中查找鍵不存在時(shí)轉(zhuǎn)而在元表中查找該鍵的功能:
mytable = setmetatable({key1 = "value1"}, --原始表
{__index = function(self, key) --重載函數(shù)
if key == "key2" then
return "metatablevalue"
end
end
})
print(mytable.key1,mytable.key2) --> output:value1 metatablevalue
關(guān)于 __index 元方法,有很多比較高階的技巧,例如:__index 的元方法不需要非是一個(gè)函數(shù),他也可以是一個(gè)表。
t = setmetatable({[1] = "hello"}, {__index = {[2] = "world"}})
print(t[1], t[2]) -->hello world
第一句代碼有點(diǎn)繞,解釋一下:先是把 {__index = {}} 作為元表,但 __index 接受一個(gè)表,而不是函數(shù),這個(gè)表中包含 [2] = "world" 這個(gè)鍵值對(duì)。 所以當(dāng) t[2] 去在自身的表中找不到時(shí),在 __index 的表中去尋找,然后找到了 [2] = "world" 這個(gè)鍵值對(duì)。
__index 元方法還可以實(shí)現(xiàn)給表中每一個(gè)值賦上默認(rèn)值;和 __newindex 元方法聯(lián)合監(jiān)控對(duì)表的讀取、修改等比較高階的功能,待讀者自己去開(kāi)發(fā)吧。
與 Java 中的 toString() 函數(shù)類(lèi)似,可以實(shí)現(xiàn)自定義的字符串轉(zhuǎn)換。
arr = {1, 2, 3, 4}
arr = setmetatable(arr, {__tostring = function (self)
local result = '{'
local sep = ''
for _, i in pairs(self) do
result = result ..sep .. i
sep = ', '
end
result = result .. '}'
return result
end})
print(arr) --> {1, 2, 3, 4}
__call 元方法的功能類(lèi)似于 C++ 中的仿函數(shù),使得普通的表也可以被調(diào)用。
functor = {}
function func1(self, arg)
print ("called from", arg)
end
setmetatable(functor, {__call = func1})
functor("functor") --> called from functor
print(functor) --> output:0x00076fc8 (后面這串?dāng)?shù)字可能不一樣)
假如我們想保護(hù)我們的對(duì)象使其使用者既看不到也不能修改 metatables。我們可以對(duì) metatable 設(shè)置了 __metatable 的值,getmetatable 將返回這個(gè)域的值,而調(diào)用 setmetatable 將會(huì)出錯(cuò):
Object = setmetatable({}, {__metatable = "You cannot access here"})
print(getmetatable(Object)) --> You cannot access here
setmetatable(Object, {}) --> 引發(fā)編譯器報(bào)錯(cuò)
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: