csdn學習筆記三:meta元表、元方法 __index, __newindex、rawset、rawget
阿新 • • 發佈:2018-12-13
重要:在表和元表的__index 和 __newindex 都沒有需要操作的key時,賦值table操作會呼叫__newindex, 取值操作會呼叫__index
元表設定setmetatable
t1 = {}; t2 = {}; print("t1=",t1); print("t2=",t2); print(setmetatable(t1,t2)); ----t2是元表 t1是普通表 列印的是t1的表 print(getmetatable(t1)); --getmetatable(t1),得到的是t2的表的地址 ----------------------------------------------------------------------- ----------------------------------------------------------------------- output: t1= table: 00719A08 t2= table: 00719A30 table: 00719A08 table: 00719A30
元方法:過載加號"+"
t1 = {1,2,3}; t2 = {4,5,6}; mt = {} mt.__add = function(a,b) local n = #a; local res = {}; for i=1,n do res[i] = a[i] + b[i]; end return res; end setmetatable(t1,mt); setmetatable(t2,mt); t3 = t1 + t2; ----__add過載了+號,所有t1可以加t2 print(t3[1]); --------------------------------------------------------------- output: 5
過載關係比較運算子"=="
a = {x=1,y=2,z=3}; b = {x=1,y=1,z=1}; mt = {} mt.__eq = function(a,b) if a[1] == b[1] and a[2] == b[2] and a[3] == b[3] then return true; else return false; end end setmetatable(a,mt); setmetatable(b,mt); if a == b then print("a == b"); --設定了元方法eq就相等 else print("a ~= b"); --如果不過載元方法eq就會不相等 end ---------------------------------------------------------------------- output: a == b
__index 元方法
這是metatable最常用的鍵,當你通過key來訪問table的時候,如果沒有這個鍵值,那麼lua就會尋找該table的metatable(假定有metatable)中的__index鍵,如果__index包含一個表,lua會在表格中查詢相應的鍵
t = {};
mt = {};
setmetatable(t,mt); ----設定mt為t的元表
print(t.x); ----t.x沒有這個鍵,然後就會去查詢mt.__index 鍵,mt也沒有這個鍵所以會返回nil
-----------------------------------
output:
nil
元表有__index鍵
t = {};
mt = {
__index = {
x = "123"
}
};
setmetatable(t,mt); ----設定mt為t的元表
print(t.x); ----t.x沒有這個鍵,然後就會去查詢mt.__index 鍵,x = "123"
---------------------------------------------------
output:
123
元表沒有__index鍵,元表有x鍵
t = {};
mt = {
x = "123"
};
setmetatable(t,mt); ----設定mt為t的元表
print(t.x); ----t.x沒有這個鍵,取值搜尋只會取元表的__index鍵,所有mt有x,t.x也是輸出nil
-----------------------------------
output:
nil
__index為函式
如果__index包含一個函式的話,且沒有取值的鍵,lua就會呼叫哪個函式,table和鍵會作為引數傳遞給函式
t = {};
mt = {
__index = function ()
print("__index function")
end
};
setmetatable(t,mt);
print(t.x);
-------------------------------------------
output:
__index function
nil
如果有函式,但是也有jian,就不執行函式
t = {};
mt = {
__index = {function ()
print("__index function")
end,
x = "100"
}
};
setmetatable(t,mt);
print(t.x);
-------------------------------------------------------
output:
100
實際當__index只有函式時,會把table和取值key傳入到__index的函式中
t = {};
print("t:",t);
mt = {
__index = function (t,k) ---
print(t,k)
if k == "x" then
t[k] = 777;
return 888;
else
return 999;
end
end
};
setmetatable(t,mt);
print(t.x); ----會把table和key傳入到__index的function中去 ,output : 888,這裡呼叫t.x沒有值,然後會給t.x賦值777
print(t.x); ----output:777 , 這裡t.x = 777
--------------------------------------------------------
output:
t: table: 00E19D00 -----這裡是t的table
table: 00E19D00 x -----這裡列印的是t的table和 t.x傳遞的x鍵名稱
888
777
__newindex元方法
__newindex元方法用來對錶進行更新(賦值),__index則用來對錶進行訪問(取值)
當你給表一個缺少的索引賦值,直譯器就會查詢__newindex元方法:如果存在則呼叫這個函式而不進行賦值操作
__newindex元方法如果是一張表,lua對這張表索引賦值操作,新的k v會出現在表中
t = { };
mt = { };
print("table t:",t); ---output: table t: table: 008E9C10
setmetatable(t,mt);
mt.__newindex = function (t,k,v) --- t.y會把 table:t,key: y,value:100 ,傳遞進去
print(t,k,v);
end
mt.__index = function (t,k) ---
if k == "x" then
t[k] = 777; ---table: 008E9C10 x 777 這裡是賦值還會呼叫一次__newindex
return 888;
else
return 999;
end
end
t.x = 100; ------output: table: 008E9C10 x 100 ,t沒有x鍵,執行了__newindex的函式但是不進行賦值
print(t.x); ------output: 888 t.x是取值不進行賦值操作,
--------------------------------------
output:
table t: table: 008E9C10
table: 008E9C10 x 100
table: 008E9C10 x 777
888
表象函式一樣呼叫(原理還是過載了方法__call)
pow = {};
setmetatable(pow,{__call = function(t,x)
return x * x ;
end})
print(pow(10));
---------------------------------
output:
100
過載__tostring方法
pow = setmetatable({10,20,30},{__tostring = function(t)
sum = 0;
for k,v in pairs(t) do
sum = sum + v;
end
return "sum = " .. sum;
end})
print(pow);
---------------------------------------------------
output:
sum = 60
rawset 和 rawget是直接操作表,而不去訪問元表
Window = {}
Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}
Window.mt = {}
function Window.new(o)
setmetatable(o ,Window.mt)
return o
end
Window.mt.__index = function (t ,key)
return 1000
end
Window.mt.__newindex = function (table ,key ,value)
if key == "wangbin" then
rawset(table ,"wangbin" ,"yes,i am") --(1)
--table.wangbin = "yes,i am" --(2)反例
end
end
w = Window.new({x = 10 ,y = 20} )
print(rawget(w ,w.wangbin)) ------取的是w表裡面的wangbin鍵,為nil
print(w.wangbin) ------沒有使用raw取的就是元表裡面的__index所以為1000
w.wangbin = "nVal" ------w沒有wangbin鍵,就執行元表裡面的__newindex的方法
print(w.wangbin) ------輸出yes,i am
rawset(w,"wangbin","nVal") ----使用rawset,就設定w表裡面的wangbin鍵位nVal
print(w.wangbin) ----輸出nVal
----------------------------------------------------
output:
nil
1000
yes,i am
nVal