lua學習筆記---元表(Metatable)
元表的作用在於對於兩個表之間的操作,改變table的行為。
1.設定/獲取元表
mytable={}
mymetatable={}
mytable=setmetatable(mytable,mymetatable)
將mymetatable設定為mytable的元表。返回值為普通表
mymetatable=getmetatable(mytable)
獲取mytable的元表,返回值為元表
2.__index元方法
當通過鍵值訪問table時,如果這個鍵沒有值,並且該table存在元表的情況下,會去查詢元表中的__index鍵。如果__index存的是一個方法,就會去執行該方法中的內容。如果是一個表,會訪問表中對應鍵值的值。具體操作流程為:
例子:
mytable={key1="c#",key2="lua"} mymetatable={key3="java"} setmetatable(mytable,mymetatable) mymetatable.__index=function(table,key) return "javaScript" end print(mytable["key3"]) print(mytable["key4"])
執行以上程式碼,打印出的結果都是javaScript。雖然mymetatable中本身有key3的值,但訪問mytable時,不會去訪問mymetatable中原有的鍵值,當發現table中不存在該鍵時,才會去訪問元表中是否有__index,這裡__index中是一個方法,所以會執行方法內容。
同樣,如果把上面mymetatable.__index換成一個表,就會去訪問該表中的鍵值元素。例mymetatable.__index={key4="c++"},這時返回的key4就成了c++.
3.__newindex
當對table進行賦值操作時,如果有元表,會執行__newindex操作.和index不同之處在於,一個對錶的讀取,一個對錶的賦值。相同處在於都是在普通表中沒有該鍵值時,新鍵值中的內容都可以是方法或者一個表。
比如上面的方法:
mytable={key1="c#",key2="lua"} mymetatable={key3="java"} setmetatable(mytable,mymetatable) mymetatable.__newindex=function(table,key,value)
print(table,key,value)
end
mytable.key5="c++"
print(mytable.key5)
這裡如果沒有元表,會直接對mytable賦值,打印出來的是c++.但有元表後會執行__newindex中的方法,不會進行賦值操作,所以打印出來為nil.這裡方法和index不同點在於有3個引數,我們可以通過
rawset(tab,key,value)---------lua內建方法,對錶賦值
lua中的這個內建函式,對引數進行賦值,效果和mytable.key5="c++"一樣。
上面對__newindex是一個方法,如果是一個表的話,會將新的鍵和值賦給該表,相當於第三個表,這個鍵值不屬於mytable,也不屬於它的元表。例:
newtable={}
mymetatable.__newindex=newtable
mytable.key5="c++"
print(mytable.key5,mymetatable.key5,newtable.key5)
得到的結果是隻有newtable.key5是c++.當然這裡mymetatable.__newindex=mymetatable也是可以的。其實原理就是:
當給table賦值時,如果該鍵值本身存在,會直接改變原鍵值元素。如果不存在,會訪問元表的_newindex,如果__newindex是一個方法,執行方法。如果是一個表,會將新的鍵值賦給這個表。
4.__add元方法
lua本身沒有對兩個表進行合併的方法,直接寫table1+table2會報錯。可以通過元表中__add鍵重寫操作。下面是例子:
table1={"java","lua","c#"} table2={"c++","php"} setmetatable(table1,{ __add=function(tab1,tab2) mi=#tab1 for k,v in pairs(tab2) do mi=mi+1 --tab1[mi]=v table.insert(tab1,mi,v) end end }) table3=table1+table2 for k,v in ipairs(table1) do print(k,v) end
這裡相當於重寫了+的操作,最終得到的結果是table1變成了:
1 java 2 lua 3 c# 4 c++ 5 php
這裡要注意的一點是,兩個相加的表只要其中有一個在元表中定義了add操作,就可以使用+來進行合併表。這裡table1+table2改變的是table1,如果改為table2+table1,變的就是table2了。
mymetatable.__index=function(table,key) return "javaScript" end print(mytable["key3"]) print(mytable["key4"])
- 1.在表中查詢,如果找到,返回該元素,找不到則繼續
- 2.判斷該表是否有元表,如果沒有元表,返回nil,有元表則繼續。
- 3.判斷元表有沒有__index方法,如果__index方法為nil,則返回nil;如果__index方法是一個表,則重複1、2、3;如果__index方法是一個函式,則返回該函式的返回值。