表的索引
也许 metatables 最重要的用途是可以改变表的索引。为此,需要考虑两个操作: 读取内容并编写表的内容。请注意,只有在表中不存在相应的键时才会触发这两个操作。
读
local meta = {}
-- to change the reading action, we need to set the '__index' method
-- it gets called with the corresponding table and the used key
-- this means that table[key] translates into meta.__index(table, key)
meta.__index = function(object, index)
-- print a warning and return a dummy object
print(string.format("the key '%s' is not present in object '%s'", index, object))
return -1
end
-- create a testobject
local t = {}
-- set the metatable
setmetatable(t, meta)
print(t["foo"]) -- read a non-existent key, prints the message and returns -1
这可用于在读取不存在的键时引发错误:
-- raise an error upon reading a non-existent key
meta.__index = function(object, index)
error(string.format("the key '%s' is not present in object '%s'", index, object))
end
写作
local meta = {}
-- to change the writing action, we need to set the '__newindex' method
-- it gets called with the corresponding table, the used key and the value
-- this means that table[key] = value translates into meta.__newindex(table, key, value)
meta.__newindex = function(object, index, value)
print(string.format("writing the value '%s' to the object '%s' at the key '%s'",
value, object, index))
--object[index] = value -- we can't do this, see below
end
-- create a testobject
local t = { }
-- set the metatable
setmetatable(t, meta)
-- write a key (this triggers the method)
t.foo = 42
你现在可以问自己如何在表中写入实际值。在这种情况下,它不是。这里的问题是元方法可以触发元方法,这会导致不定式循环,或更确切地说,堆栈溢出。那我们怎么解决这个问题呢?解决方案称为原始表访问。