在Lua table中我们可以访问对应的key来得到value值,但是却无法对两个table直接进行操作。

因此Lua提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。元表就是一种存放了元方法的table,我们可以通过对应的Key来得到value的值,作用就是修改一个值的行为(这就是元方法)。

下面的__add、__index等都是两个两个下划线(“__”)千万注意

如例:

local mytable1 = {1};
local mytable2 = {2};

local mytable3 =  mytable1 + mytable2;

如果对两个table直接进行“+”操作,就会报错。

lua 用元方法赋值 lua中的元表_lua 用元方法赋值

因为程序不知道如何对两个表进行操作,这时候就需要通过元表来定义如何执行“+”操作了

local mt = {}
mt.__add = function(t1,t2)
    print("aaa");
end

local mytable1 = {1};
local mytable2 = {2};
mytable1 = setmetatable(mytable1,mt);

local mytable3 =  mytable1 + mytable2;

输出结果为:aaa

如果我们为mytable1和mytable2都设置上元表会怎样:

local mt = {}
mt.__add = function(t1,t2)
    print("aaa");
end
local mt1 = {};
mt1.__add = function(t1,t2)
    print("bbb");
end

local mytable1 = {1};
local mytable2 = {2};
mytable1 = setmetatable(mytable1,mt);
mytable2 = setmetatable(mytable2,mt1);
local mytable3 =  mytable1 + mytable2;

结果没有变还是:aaa

但是将mytable1 = setmetatable(mytable1,mt);注释后就是bbb了,所以我们得出他的执行顺序是:

  1. 查看mytable1是否有元表,若有,则查看mytable1的元表是否有__add元方法,若有则调用。
  2. 查看mytable2是否有元表,若有,则查看mytabl2的元表是否有__add元方法,若有则调用。
  3. 完蛋,报错了。

元表中的元方法


lua 用元方法赋值 lua中的元表_lua 用元方法赋值_02

来自菜鸟教程的截图

此外还有:


lua 用元方法赋值 lua中的元表_赋值_03

blueberryzzz

上面的加减乘除做法基本类似不做过多的解释。

__index

这是metatable 最常用的键,当访问表中不存的字段 ,会用到这个元方法。__index可以是一个函数也可以是一个table。

函数版:

local mt = {}
mt.__index = function(t,key)
    return key;
end
local mytable1 = {};
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);

输出:

lua 用元方法赋值 lua中的元表_lua_04

第一个为nil是自己的表没有指定key的索引,第二个在元表中找到。

table版:

local mt = {}
mt.__index = {key = "hhhh"}

local mytable1 = {};
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);

输出:

lua 用元方法赋值 lua中的元表_lua_05

执行的过程:

  1. 在表中查找,找到则返回,找不到则继续
  2. 判断是否有元表,没有返回nil,有则继续
  3. 判断元表有无__index方法,如果该方法为nil,则返回nil;如果是一个表,则重复1、2、3操作;

__newindex

如果我们给表中不存在的字段赋值的时候,则会调用__newindex。上面我们提到如果在表中查询表中不存在的键时会调用__index,但是给表中不存在的字段赋值时依然不会出现错误。此时会调用__newindex元方法。__newindex可以是一个函数也可以是一个table。

函数版:

__newindex是一个函数时会将赋值语句中的表、索引、赋的值当作参数去调用。不对表进行改变

local mt = {}
mt.__newindex = function (t, key, value)
    print("key is ".. key);
    print("value is"..value)
end

local mytable1 = {key = "Myvalue"};
--表中key可以输出
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
--为表中不存在的key赋值,会调用元表中的__newindex方法(仅仅是调用元表中的__newindex,不会对本来的表进行改变)
mytable1.newKey = 12;
print(mytable1.newKey);

输出结果:

lua 用元方法赋值 lua中的元表_字段_06

table版:

__newindex是一个table时,为t中不存在的索引赋值会将该索引和值赋到__newindex所指向的表中,不对原来的表进行改变。

local mt = {}
mt.__newindex = {}

local mytable1 = {key = "Myvalue"};
--表中key可以输出
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
--为表中不存在的key赋值,会调用元表中的__newindex方法(仅仅是调用元表中的__newindex,不会对本来的表进行改变)
mytable1.newKey = 12;
print(mytable1.newKey);

输出结果:

lua 用元方法赋值 lua中的元表_元表_07

rawget

rawget可以让你直接获取到表中索引的实际值,而不通过元表的__index元方法。

local mt = {}
mt.__newindex = {}
mt.__index = {key="123"}

local mytable1 = {};
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
print(rawget(mytable1,"key"))

结果:

lua 用元方法赋值 lua中的元表_lua_08

rawset

rawset可以让你直接为表中索引的赋值,而不通过元表的__newindex元方法。

local mt = {}
mt.__newindex = {}

local mytable1 = {};
mytable1 = setmetatable(mytable1,mt);

print(mytable1.key);
rawset(mytable1,"key","123")
print(mytable1.key);

结果:

lua 用元方法赋值 lua中的元表_lua_09

__call

__call 元方法在 Lua 调用一个值时调用。

local mt = {}
--__call的第一参数是表自己
mt.__call = function(t,...)
    --输出所有参数
    for key,value in ipairs{...} do
        print(value)
    end
end

local mytable1 = {};
setmetatable(mytable1,mt);
mytable1(1,2,3)

__tostring 

__tostring 元方法用于修改表的输出行为。

local mt = {}
mt.__tostring = function(t)
    local sum = 0;
    for key,value in ipairs(t) do
        sum = sum + value;
    end
    return sum;
end

local mytable1 = {1,2,3};
setmetatable(mytable1,mt);
print(mytable1);