表的索引

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

你現在可以問自己如何在表中寫入實際值。在這種情況下,它不是。這裡的問題是元方法可以觸發元方法,這會導致不定式迴圈,或更確切地說,堆疊溢位。那我們怎麼解決這個問題呢?解決方案稱為原始表訪問