Lua元表(Metatable)简易教程
文章目錄
- 0.友情鏈接
- 1.引言
- 2.創建一個元表
- 2.1.__tostring方法
- 2.2.__add和__mul方法
- 2.3.__index方法
- 2.4.__call方法
- 3.完整代碼
0.友情鏈接
- GitHUb上下載Lua編譯器
- Lua菜鳥教程中的元表介紹(較全,但功能性受限)
- 博客園內元表的介紹(較詳細)
- 簡書內元表的介紹(較簡潔)
1.引言
\qquadLua語言是用C寫的,Lua的元表類似于Python的類,但書寫難度遠比Python的Class大,加上Lua沒有免費的Debugger,這個問題就讓人很頭疼。在此寫一個可以使用多個“方法”的元表(Metatable),代碼較短,但容易理解,希望能幫到大家。
\qquad簡單理解一個Lua語言的Metatable(元表),Metatable是table的一個拓展,setmetatable是創建一個Metatable的函數,它有兩個參數——原table和Metatable的屬性、方法列表。我們從這兩方面出發創建一個Metatable。不熟悉Luatable操作的讀者,建議查看以下的簡短的教程鏈接:
Lua的table簡介
2.創建一個元表
vector = {} -- 空屬性 a = setmetatable({1,2,3},vector) -- create vector a b = setmetatable({4,5,6},vector) -- create vector b\qquad這樣我們就創建一個空屬性的列表,對他們的操作和table是一樣的,現在我們要定義table的屬性和方法了(即vector),創建了屬性和方法的Metatable相當于繼承了table的一個Lua類,我們先從簡單的開始。
2.1.__tostring方法
\qquad__tostring方法是Metatable轉換為字符串的方法,print一個Metatable時,就查看Metatable有無此方法,若沒有,則會打印出一個table的編號;若有,則會按照此方法進行。
\qquad在此介紹一個簡單的方法,先定義一個有函數指針的Lua函數,再將這個函數指針加入vector,即完成了Metatable對__tostring方法的繼承。值得注意的是,當作為vector類的方法時,v_print函數的參數vector傳遞的參數就和python的self一樣,傳遞的是元表本身。
運行這個Lua程序,得到的結果如下:
>lua -e "io.stdout:setvbuf 'no'" "EX5.lua" 1,2,3 4,5,6 table: 00A00920 >Exit code: 0如果你成功了,那么恭喜你,你已經掌握了一半元表的知識。
2.2.__add和__mul方法
\qquad實際上,元表的操作方法有很多,具體就是用操作符來代替調用函數的方法,我們在此只介紹兩個——加法和乘法。按照之前的套路,先定義加法和乘法的函數,與之不同的是,加法和乘法都是雙目運算符,因此參數數目是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)運行結果如下:
>lua -e "io.stdout:setvbuf 'no'" "Test1.lua" 5,7,9 32 >Exit code: 0\qquad這里定義的加法,返回的仍然是Metatable類,所以打印出的結果仍然不是table的編號
其余的操作符方法類似,在此不再贅述
| __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官方文檔對于__index方法的解釋是,若在元表中未找到對應的key(鍵值),則調用__index方法查找,文字敘述較為生疏,下面是一個例子:
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"])輸出結果如下
>lua -e "io.stdout:setvbuf 'no'" "Test2.lua" 1,2,3 6 >Exit code: 0\qquad可以發現,元表a中并沒有"sum"這個鍵,所有程序調用__index方法,成功找到了鍵"sum"對應的value(這里是一個函數返回的值)。但是值得注意的是,這個方法并不支持多參數的傳入,如果需要,請看下文。
2.4.__call方法
\qquad__call方法容許元表像函數用于使用,類似像a(para1,para2)的形式,和前面的方法一樣,第一個參數默認傳遞的是a本身,但在調用的時候省略(與python的方法調用一致)。還是一樣,先看一段簡短的程序加深理解。
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"))輸出結果:
>lua -e "io.stdout:setvbuf 'no'" "Test3.lua" 1,2,3 4,5,6 4,10,18 >Exit code: 0\qquad我們使用__call方法串入了兩個參數,一個是Metatable b,還有一個是方法“mul”,雖然他是字符串,但在v_call中,它表示調用了v_mul方法。
3.完整代碼
\qquad在此附上完整的代碼及輸出結果,方便讀者對照理解。
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"))輸出結果:
>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希望本文對您有幫助,感謝您的閱讀。
總結
以上是生活随笔為你收集整理的Lua元表(Metatable)简易教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android下 布局加边框 指定背景色
- 下一篇: GO国内镜像加速模块下载