什么是元表?
元表 是一个普通的表,可以附加到另一个表 上,用来定义该表在某些特定操作下的行为。当 Lua 对表进行某些操作(如相加、索引、调用等)时,如果该表有元表,Lua 就会查看元表中是否有对应的元方法来决定如何执行操作。
可以起到一个类似于c++中运算符重载的作用
Lua
tt1={1,2,3,4};
tt2={5,6,7,8,9,10};
meT3={};
for index, value in ipairs(tt1) do
print(index,value);
end
meT3.__add=function (t1,t2)
local count=0;
local res={}
if(#t1<#t2)then
count=#t2;
else
count=#t1;
end
for i=1,count do
if(i<=#t1)and(i<=#t2)then
res[i]=t1[i]+t2[i];
elseif i<=#t1 then
res[i]=t1[i];
elseif i<=#t2 then
res[i]=t2[i];
end
end
return res;
end
setmetatable(tt1,meT3);
setmetatable(tt2,meT3);
tt3=tt1+tt2;
print("");
for index, value in ipairs(tt3) do
print(index,value);
end
运行结果:
Lua
1 1
2 2
3 3
4 4
1 6
2 8
3 10
4 12
5 9
6 10
__index的用法
元表中有键值,table中也有键值,会优先调用table中的键值;table中没有键值的话,会调用元表中的键值
Lua
t1={id=123,name="Tom"};
met={
__index={age="999"};
};
print(t1.age);
t1.age="789";
print(t1.age);
setmetatable(t1,met);
print(t1.age);
t1.age=nil;
print(t1.age);
运行结果:
Lua
nil
789
789
999
元表中的"__index"是一个函数时
Lua
t1={id=123,name="Tom"};
met={
__index=function (k,v)
k[v]="aaa";
return "bbb";
end
};
print(t1.age);
setmetatable(t1,met);
print(t1.age);
print(t1.age);
t1.age=nil;
print(t1.age);
print(t1.age);
运行结果:
Lua
nil
bbb
aaa
bbb
aaa
__newindex的用法
如果是表,则在表里面设一个没有的key值的时候,会写到__newindex 对应的表中,而不会写到本表中;如果本表中有key值,则会更新本表,不会管元表。如果是function ,则直接调用,且本表,key,value都可以作为参数
Lua
t1={id=123,name="Tom"};
t2={};
met={
__index={age="hhh";};
__newindex=t2;
};
setmetatable(t1,met);
print(t1.age);
print("");
t1.age="567";
print(t1.age);
print(t2.age);
met.__index=t2;
print(t1.age);
print(t2.age);
运行结果:
Lua
hhh
hhh
567
567
567
是function的使用方式
Lua
t1={id=123,name="Tom"};
t2={};
met={
__index={age="hhh";};
__newindex=function (t,k,v)
rawset(t,k,v);
end
};
setmetatable(t1,met);
print(t1.age);
print("");
t1.age="567";
print(t1.age);
print(t2.age);
met.__index=t2;
print(t1.age);
print(t2.age);
运行结果:
Lua
hhh
567
nil
567
nil
__index与__newindex对比

基本对比示例
Lua
local t = {existing = "已有值"}
local mt = {
-- __index: 当访问不存在的键时调用
__index = function(table, key)
print("__index 被调用,键: " .. key)
return "默认值 for " .. key
end,
-- __newindex: 当设置不存在的键时调用
__newindex = function(table, key, value)
print("__newindex 被调用,键: " .. key .. ", 值: " .. value)
-- 注意:这里没有实际设置值!
end
}
setmetatable(t, mt)
print("1. 访问已存在的键:")
print(t.existing) -- 输出: 已有值 (不触发元方法)
print("\n2. 访问不存在的键:")
print(t.name) -- 触发 __index
-- 输出:
-- __index 被调用,键: name
-- 默认值 for name
print("\n3. 设置不存在的键:")
t.age = 25 -- 触发 __newindex
-- 输出: __newindex 被调用,键: age, 值: 25
print("\n4. 再次访问刚才设置的键:")
print(t.age) -- 仍然触发 __index! (因为值没有被实际设置)
-- 输出:
-- __index 被调用,键: age
-- 默认值 for age
__tostring 的用法
__tostring 用函数接管本表的返回值,返回一个string
Lua
t1={id=123,name="Tom"};
met={
__tostring=function (t)
str="";
for key, value in pairs(t) do
str=str..key..":\t"..value.."\n";
end
return str;
end
};
print(t1);
setmetatable(t1,met);
print(t1);
运行结果:
Lua
table: 000000000260b5a0
name: Tom
id: 123
__call 的用法
类似于默认构造
Lua
t1={id=123,name="Tom"};
met={
__call=function (t,...)
local tt={...}
for key, value in pairs(t) do
print(key,value);
end
for key, value in pairs(tt) do
print(key,value);
end
end
};
setmetatable(t1,met);
t1(1,2,3,"io","900");
运行结果:
Lua
name Tom
id 123
1 1
2 2
3 3
4 io
5 900
rawget(t,str) 是获取本表 t 中 str 的值,不是获取元表中的值
Lua
t1={id=123,name="Tom"};
met={
__index={age="123"};
};
print(t1.name);
print(t1.age);
setmetatable(t1,met);
print("");
print(t1.name);
print(t1.age);
print("");
print(rawget(t1,"name")); --获取本表中的值
print(rawget(t1,"age"));
运行结果:
Lua
Tom
nil
Tom
123
Tom
nil