1.Meatatable(元表)
metatable是table预定义的一系列操作。比如将两个table相加,那么Lua会先去检查两个table中是否有metatable,然后在检查metatable是否有__add
方法,如果有就按照__add
方法中的操作来执行,否则会报错。
Lua中的新建的table的时候是不会创建metatable的,需要使用setmetatable()
来设置元表。
注意:setmetatable()
可以是任意的table,包括要赋值的table本身。
Lua中检查是否有元表使用getmetatable()
print(getmetatable(nil)); // 输出为:nil,表示nil没有元表
实现table+
的运算
Set = {};
function Set.new(t)
local set = {};
for i, v in ipairs(t) do
set[i] = v;
end
return set;
end
function Set.union(a, b)
local res = {};
for k, in pairs(a) do
res[k] = true;
end
for k, in pairs(b) do
res[k] = true;
end
return res;
end
function Set.tostring(set)
local str = "{";
local sep = "";
for k, v in pairs(set) do
str = str..sep..k;
sep = ",";
end
return s.."}";
end
// 输出函数
function Set.print(set)
print(Set.tostring(set));
end
// 设置元表
Set.mt = {};
setetatable(Set, Set.mt);
// 设置Set的元表`__add`元方法指向的`Set.union`函数
Set.mt.__add = Set.union;
// 测试Set
s1 = Set.new({10,20,30,50});
s2 = Set.new(30,1);
s3 = s1 + s2;
Set.print(s3); // 输出为:1,20,30,50,20
2.元方法
table还有其他的元方法(元表的方法),罗列如下:
__index // 默认值
function(table,key)
__newindex // 赋值
function(table,key,value)
__tostring // 被print()调用
__metatable // 设置后可隐藏mt
__eq // 等于
__lt // 小于
__le // 小于等于
__add // 加
__sub // 减
__mul // 乘
__div // 除
__unm // 负
__pow // 幂
__concat // 连接
重要的元方法介绍
1.__index
元方法
Lua中访问table元素是先通过__index
元方法先查找是否有这个函数,如果没有就返回nil
。
__index
的值可以是一个table或者函数,如果是table则会以该table作为索引进行查询,若是函数,则将table和缺少的域作为参数调用这个函数。
Window = {};
Window.mt = {};
Window.prototype = {x = 0, y = 0, width = 100, height = 100};
Window.mt.__index = function(table,key)
return Window.prototype[key];
end
function Window.new(t)
setmetatable(t,Window.mt);
return t;
end
// 测试
w = Window.new({x = 10,y = 20});
print(w.height); // 输出为:100
2.__newindex
元方法
__newindex
用于table的更新,__index
用于table的查询操作,当对table中不存在的索引赋值时,就会调用__newindex
元方法
Window = {};
Window.mt = {};
Window.mt.__newindex = function(table,key,value)
print("update of element"..tostring(key)..tostring(value));
rawset(table,key,value);
end
function Window.new(t)
setmetatable(t,Window.mt);
return t;
end
// 测试
window = Window.new({x = 10,y = 20});
window.a = 10;
总结:
__index
在get
表中未定义元素时触发,对应有rawset(table,key)
来避免调用__index
;
__newindex
在set
表中未定义元素时触发,对应有的rawset(table,key)
来避免调用__newindex