当我们只想单纯的调用table里的字段或者给table字段赋值时,我们可以通过rawget函数来忽略元表的__index作用,只从table中
查找例如:
local father = {
--house=1,
sayHello = function()
print("大家好,我是father.");
end
}
local temp ={
__index = father,
__newindex = function(table, key)
print(key .. "字段是不存在的,不允许给它赋值!");
end
}
son = {
car=1
}
setmetatable(son, temp) --把son的metatable设置为father
print(rawget(son, "house"));
print(rawget(son, "car"));
rawset(son, "house", "10");
rawset(son, "sayHello", function()
print('============')
end);
print(son.house);
son.sayHello()
上面代码输出:
nil
1
10
============
rawget函数的第一个参数是要调用的table,第二个参数是table的字段名。
因此,通过rawget调用son的house字段,返回nil,而调用car字段,则能正确取得值。
同样的是,rawset函数可以忽略元表的__newindex功效,单纯地给house赋值
另外在网上看到有个人用__index和__newIndex实现了一个只读的函数,挺有意思的这里贴一下
local function readOnly(t)
local newT = {};
local mt = {
__index = t,
__newindex = function()
error("别修改我!我是只读的!");
end
}
setmetatable(newT, mt);
return newT;
end
local days = readOnly({"星期一", "星期二", "星期日"});
days[2] = "星期三哪去了啊?" ;
输出:[LUA-print] LUA ERROR: [string "src/main.lua"]:130: [string "src/main.lua"]:76: 别修改我!我是只读的!
没错,通过readOnly产生的table,是无法进行赋值操作的。
那么,原理呢?我们来一步步思考吧:
a.首先,readOnly会创建一个新的table,然后把我们传进去的table作为__index元方法。
b.元表里还增加了__newindex,用来阻止不存在字段的赋值操作。
c.readOnly返回的table已经不是我们原来的table了,它是一个空的table,但是它被设置了一个新的元表。
d.开始对days执行赋值操作:days[2] = “星期三哪去了啊?” 。
e.days是一个空的table,所以它不存在这个字段,也因此,会调用__newindex元方法,赋值失败。
f.如果只是调用days,不进行赋值,如:print(days[2]); 则能正常输出字段值,因为days的元表里有__index元方法。虽然days中不存在2这个字段,但是可以通过__index找到这个字段。
总而言之,最终,days成为了一个只可以读取,不能进行赋值操作的table。
节选自:https://www.jb51.net/article/55160.htm