表的索引

也许 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

你现在可以问自己如何在表中写入实际值。在这种情况下,它不是。这里的问题是元方法可以触发元方法,这会导致不定式循环,或更确切地说,堆栈溢出。那我们怎么解决这个问题呢?解决方案称为原始表访问