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

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