Ответ, как обычно для очень интересного кода в Lua, более метатабельный.
Когда ваш метаметод __index
на самом деле является таблицей, Lua просто делает стандартный доступ к таблице для данной таблицы. Это означает, что вы можете установить метатабель на своем метатабиле. Затем вы можете установить метаметод __index для этого «мета-метатабеля».
foo = function()
print("foo")
end
bar = function(_, key)
return function()
print(string.format("bar: %s", key))
end
end
mmt = { __index = bar }
mti = { foo = foo }
mt = { __index = mti }
t = {}
setmetatable(mti, mmt)
setmetatable(t, mt)
t.foo() -- prints: "foo"
t.bar() -- prints: "bar: bar"
t.baz() -- prints: "bar: baz"
При этом, когда вы пытаетесь получить доступ к полю, которое отсутствует в обеих таблицах, lua сначала попытается получить доступ к таблице верхнего уровня, которая получит доступ к первому метатабилю, который затем вызовет ваш метаметод во втором метатабле.
Существует также другой, возможно, более прямой ответ: используйте метаметод __index
, чтобы проверить другую таблицу на предмет именованных полей:
foo = function()
print("foo")
end
f = { foo = foo }
bar = function(_, key)
if f[key] then return f[key] end
return function()
print(string.format("bar: %s", key))
end
end
mt = { __index = bar }
t = {}
setmetatable(t, mt)
t.foo() -- prints: "foo"
t.bar() -- prints: "bar: bar"
t.baz() -- prints: "bar: baz"
Проверено на Lua 5.3.