Lua / Luajit: индексирование и именованный метод одновременно? - PullRequest
0 голосов
/ 29 октября 2018

В учебнике Lua PIL и Luajit FFI в метатаблице было два использования __index.

Один предназначен для индексации, например obj [123], например,

__index = function (self, k) return self._data+(k-self._lower)

Другое использование - определение именованных методов, как указано в руководстве,

__index = { area = function(a) return a.x*a.x + a.y*a.y end, },

Затем мы можем вызвать функцию как obj:area().

Могу ли я одновременно выполнять оба действия, например прямую индексацию и именованные методы?

1 Ответ

0 голосов
/ 30 октября 2018

Ответ, как обычно для очень интересного кода в 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.

...