Lua元表(Metatable)简易教程
文章目錄
- 0.友情鏈接
- 1.引言
- 2.創(chuàng)建一個(gè)元表
- 2.1.__tostring方法
- 2.2.__add和__mul方法
- 2.3.__index方法
- 2.4.__call方法
- 3.完整代碼
0.友情鏈接
- GitHUb上下載Lua編譯器
- Lua菜鳥(niǎo)教程中的元表介紹(較全,但功能性受限)
- 博客園內(nèi)元表的介紹(較詳細(xì))
- 簡(jiǎn)書(shū)內(nèi)元表的介紹(較簡(jiǎn)潔)
1.引言
\qquadLua語(yǔ)言是用C寫(xiě)的,Lua的元表類(lèi)似于Python的類(lèi),但書(shū)寫(xiě)難度遠(yuǎn)比Python的Class大,加上Lua沒(méi)有免費(fèi)的Debugger,這個(gè)問(wèn)題就讓人很頭疼。在此寫(xiě)一個(gè)可以使用多個(gè)“方法”的元表(Metatable),代碼較短,但容易理解,希望能幫到大家。
\qquad簡(jiǎn)單理解一個(gè)Lua語(yǔ)言的Metatable(元表),Metatable是table的一個(gè)拓展,setmetatable是創(chuàng)建一個(gè)Metatable的函數(shù),它有兩個(gè)參數(shù)——原table和Metatable的屬性、方法列表。我們從這兩方面出發(fā)創(chuàng)建一個(gè)Metatable。不熟悉Luatable操作的讀者,建議查看以下的簡(jiǎn)短的教程鏈接:
Lua的table簡(jiǎn)介
2.創(chuàng)建一個(gè)元表
vector = {} -- 空屬性 a = setmetatable({1,2,3},vector) -- create vector a b = setmetatable({4,5,6},vector) -- create vector b\qquad這樣我們就創(chuàng)建一個(gè)空屬性的列表,對(duì)他們的操作和table是一樣的,現(xiàn)在我們要定義table的屬性和方法了(即vector),創(chuàng)建了屬性和方法的Metatable相當(dāng)于繼承了table的一個(gè)Lua類(lèi),我們先從簡(jiǎn)單的開(kāi)始。
2.1.__tostring方法
\qquad__tostring方法是Metatable轉(zhuǎn)換為字符串的方法,print一個(gè)Metatable時(shí),就查看Metatable有無(wú)此方法,若沒(méi)有,則會(huì)打印出一個(gè)table的編號(hào);若有,則會(huì)按照此方法進(jìn)行。
\qquad在此介紹一個(gè)簡(jiǎn)單的方法,先定義一個(gè)有函數(shù)指針的Lua函數(shù),再將這個(gè)函數(shù)指針加入vector,即完成了Metatable對(duì)__tostring方法的繼承。值得注意的是,當(dāng)作為vector類(lèi)的方法時(shí),v_print函數(shù)的參數(shù)vector傳遞的參數(shù)就和python的self一樣,傳遞的是元表本身。
運(yùn)行這個(gè)Lua程序,得到的結(jié)果如下:
>lua -e "io.stdout:setvbuf 'no'" "EX5.lua" 1,2,3 4,5,6 table: 00A00920 >Exit code: 0如果你成功了,那么恭喜你,你已經(jīng)掌握了一半元表的知識(shí)。
2.2.__add和__mul方法
\qquad實(shí)際上,元表的操作方法有很多,具體就是用操作符來(lái)代替調(diào)用函數(shù)的方法,我們?cè)诖酥唤榻B兩個(gè)——加法和乘法。按照之前的套路,先定義加法和乘法的函數(shù),與之不同的是,加法和乘法都是雙目運(yùn)算符,因此參數(shù)數(shù)目是2.
v_print = function(vec) -- print(v_print)return table.concat(vec,',')end v_add = function(vec,new_vec) -- vector_a + vector_blocal result = setmetatable({},vector)for i = 1,#new_vec doresult[i] = vec[i]+new_vec[i]endreturn resultend v_dot = function(vec,new_vec) --vector_a·vector_b (inner product)local product = 0for i,v in ipairs(vec) doproduct = product + v*new_vec[i]endreturn productend vector = {__tostring=v_print,__add=v_add,__mul=v_dot} a = setmetatable({1,2,3},vector) -- create vector a b = setmetatable({4,5,6},vector) -- create vector b print(a+b) print(a*b)運(yùn)行結(jié)果如下:
>lua -e "io.stdout:setvbuf 'no'" "Test1.lua" 5,7,9 32 >Exit code: 0\qquad這里定義的加法,返回的仍然是Metatable類(lèi),所以打印出的結(jié)果仍然不是table的編號(hào)
其余的操作符方法類(lèi)似,在此不再贅述
| __add | a+b |
| __sub | a-b |
| __mul | a*b |
| __div | a/b |
| __mod | a%b |
| __unm | -a |
| __concat | ..\text{..}.. |
| _eq | a==b |
| __lt | a<b |
| __le | a<=b |
2.3.__index方法
\qquad官方文檔對(duì)于__index方法的解釋是,若在元表中未找到對(duì)應(yīng)的key(鍵值),則調(diào)用__index方法查找,文字?jǐn)⑹鲚^為生疏,下面是一個(gè)例子:
v_print = function(vec) -- print(v_print)return table.concat(vec,',')end v_sum = function(vec) -- sum of a veclocal sum = 0for i,v in ipairs(vec) dosum = sum+vendreturn sumend v_index = function(vec,value) -- value method of a vecif value == "sum" thenreturn v_sum(vec)endend vector = {__index = v_index,__tostring = v_print} a = setmetatable({1,2,3},vector) -- create vec a print(a) print(a["sum"])輸出結(jié)果如下
>lua -e "io.stdout:setvbuf 'no'" "Test2.lua" 1,2,3 6 >Exit code: 0\qquad可以發(fā)現(xiàn),元表a中并沒(méi)有"sum"這個(gè)鍵,所有程序調(diào)用__index方法,成功找到了鍵"sum"對(duì)應(yīng)的value(這里是一個(gè)函數(shù)返回的值)。但是值得注意的是,這個(gè)方法并不支持多參數(shù)的傳入,如果需要,請(qǐng)看下文。
2.4.__call方法
\qquad__call方法容許元表像函數(shù)用于使用,類(lèi)似像a(para1,para2)的形式,和前面的方法一樣,第一個(gè)參數(shù)默認(rèn)傳遞的是a本身,但在調(diào)用的時(shí)候省略(與python的方法調(diào)用一致)。還是一樣,先看一段簡(jiǎn)短的程序加深理解。
v_call = function(vec,new_vec,value) -- vec(...)if value == nil thenfor i,v in ipairs(new_vec) dovec[i] = vendreturn vecendif value == "mul" thenreturn v_mul(vec,new_vec)endend v_print = function(vec) -- print(v_print)return table.concat(vec,',')end v_mul = function(vec,new_vec) -- vec_a.*vec_b (dot multiply)local result = setmetatable({},vector)for i,v in ipairs(vec) doresult[i] = v*new_vec[i]endreturn resultend vector = {__tostring=v_print,__call=v_call} a = setmetatable({1,2,3},vector) -- create vector a b = setmetatable({4,5,6},vector) -- create vector b print(a) print(b) print(a(b,"mul"))輸出結(jié)果:
>lua -e "io.stdout:setvbuf 'no'" "Test3.lua" 1,2,3 4,5,6 4,10,18 >Exit code: 0\qquad我們使用__call方法串入了兩個(gè)參數(shù),一個(gè)是Metatable b,還有一個(gè)是方法“mul”,雖然他是字符串,但在v_call中,它表示調(diào)用了v_mul方法。
3.完整代碼
\qquad在此附上完整的代碼及輸出結(jié)果,方便讀者對(duì)照理解。
v_add = function(vec,new_vec) -- vec_a + vec_blocal result = setmetatable({},vec)for i = 1,#new_vec doresult[i] = vec[i]+new_vec[i]endreturn resultend v_call = function(vec,new_vec,value) -- vec(...)if value == nil thenfor i,v in ipairs(new_vec) dovec[i] = vendreturn vecendif value == "mul" thenreturn v_mul(vec,new_vec)endend v_print = function(vec) -- print(v_print)return table.concat(vec,',')end v_mul = function(vec,new_vec) -- vec_a.*vec_b (dot multiply)local result = setmetatable({},vector)for i,v in ipairs(vec) doresult[i] = v*new_vec[i]endreturn resultend v_dot = function(vec,new_vec) --vec_a·vec_b (inner product)local product = 0for i,v in ipairs(vec) doproduct = product + v*new_vec[i]endreturn productend v_sum = function(vec) -- sum of a veclocal sum = 0for i,v in ipairs(vec) dosum = sum+vendreturn sumend v_index = function(vec,value) -- value method of a vecif value == "sum" thenreturn v_sum(vec)endend vector = {__add=v_add,__call = v_call,__tostring=v_print,__mul=v_dot,__index=v_index} a = setmetatable({1,2,3},vector) -- create vec a b = setmetatable({4,5,6},vector) -- create vec b print(a) print(b) print(table.concat(a+b,",")) print(a*b) print(a["sum"]) print(a(b,"mul"))輸出結(jié)果:
>lua -e "io.stdout:setvbuf 'no'" "EX5.lua" 1,2,3 4,5,6 5,7,9 32 6 4,10,18 >Exit code: 0希望本文對(duì)您有幫助,感謝您的閱讀。
總結(jié)
以上是生活随笔為你收集整理的Lua元表(Metatable)简易教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android下 布局加边框 指定背景色
- 下一篇: GO国内镜像加速模块下载