1. 程式人生 > >lua學習筆記---元表(Metatable)

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方法是一個函式,則返回該函式的返回值。