csdn学习笔记三:meta元表、元方法 __index, __newindex、rawset、rawget

版权声明: https://blog.csdn.net/qq_28710983/article/details/82943918

重要:在表和元表的__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

猜你喜欢

转载自blog.csdn.net/qq_28710983/article/details/82943918
今日推荐