在Lua中的每個值都有一套預定義的操作集合。例如可以將數字相加,可以連接字符串,還可以在table中插入一對key-value等。但是我們無法將兩個table相加,無法對函數作比較,也無法調用一個字符串。
但是,Lua提供了元表與元方法來修改一個值的行為,使其在面對一個非預定義的操作時執行一個指定的操作。例如,假設a和b都是table,通過元表可以定義如何計算表達式a+b。當Lua試圖將兩個table相加時,它會先檢查兩者之一是否有元表,然后檢查該元表中是否有一個叫__add的字段。如果找到了該字段,就調用該字段對應的值。這個值也就是所謂的”元方法“,它應該是一個函數,用於計算table的和。
Lua在創建一個新的table時不會創建元表。因此有兩個函數可以獲取與設置元表:
setmetatable( t1,t2 ) 設置t1的元表為t2。
getmetatable( t ) 獲取t的元表。
任何table都可以作為任何值的元表,而一組相關的table也可以共享一個通用的元表,此元表描述了它們共同的行為。一個table甚至可以作為它自己的元表,用於描述其特有的行為。總之,任何搭配形式都是合法的。
在Lua中可以定義值的行為,那么就有相應的元方法:算術類的元方法、關系類的元方法、庫定義的元方法以及table訪問的元方法。
1、算術類的元方法:__add(加)、__sub(減)、__mul(乘)、__div(除)、__unm(相反數)、__mod(取模)、__pow(乘冪)、__concat(連接操作符)
2、關系類的元方法:__eq(等於)、__lt(小於)、__le(小於等於)
3、庫定於的元方法:__tostring(print時調用)、__metatable(設置后不可修改元表)
4、table訪問的元方法:__index(查詢table)、__newindex(修改table的字段)
、__mode(弱引用table)
在對table使用算術操作符時,Lua回去查找有沒有操作符對應的元方法,如果有則調用算術類元方法,否則會產生錯誤信息。如
table1 = { x=1 } table2 = { x=2 } print( table1 - table2 ) --產生錯誤:attempt to perform arithmetic on global 'table1' (a table value)
如果設置了元表及元方法,就可以按照自己的意願去處理(減法求值的例子):

關系類的元方法在使用上同算術類的元方法一樣,都是在有操作符操作時去查詢元方法,其中有三個關系操作符沒有單獨的元方法,Lua會把
1、a~=b 轉化為 not( a==b )
2、a>b 轉化為 b<a
3、a>=b 轉化為 b<=a
庫定義的元方法的應用:__tostring

庫定義的元方法的應用:__metatable

table訪問的元方法:__index。當訪問一個table中不存在的字段時,得到的結果為nil。這是對的,但並非完全正確。實際上,這些訪問會促使解釋器去查找一個叫__index的元方法。如果沒有這個元方法,那么訪問結果就是nil,否則,就由這個元方法來提供最終的結果。

table訪問的元方法:__newindex。當對一個table中不存在的索引賦值時,解釋器就會查找__newindex元方法。如果有這個元方法,解釋器就調用它,而不是執行賦值。注意,Lua中有一個rawset(t,k,v)方法可以繞過元方法直接對table進行賦值。

通過table訪問的元方法,__index、__newindex搭配使用可以很輕易的實現面向對象。元方法在元表中設置,只有當table被設置為元表時,table中的元方法才會有效。
table訪問的元方法:__mode。設置table為弱引用table,並確定是key為弱引用或者value為弱引用。所謂若引用就是一種會被垃圾收集器忽視的對象引用。如果一個對象的所有引用都是弱引用,那么Lua就可以回收這個對象了,並且還可以以某種形式來刪除這些弱引用本身。Lua用“弱引用table”來實現弱引用,一個弱引用table就是一個具有弱引用條目的table。如果一個對象只被一個弱引用table所持有,那么最終Lua是會回收這個對象的。
一個table的弱引用類型是通過其元表中的__mode字段來決定的。這個字段的值為一個字符串:'k'(table的key是弱引用)、'v'(table中value是弱引用)。只要有一個key或value被回收了,那么它們所在的整個條目都會從table中刪除。
tab1 = {} tab2 = { __mode = 'k' } --tab1中的key將會是弱引用 setmetatable( tab1,tab2 )