Ответ 1
anotherObject:aFunction(variable, object.doStuff)
- правильный синтаксис.
Использование двоеточия :
с функцией - это просто синтаксический сахар для вызова или объявления с неявным параметром self
в качестве первого аргумента. Если вы хотите следовать шаблону, который вы показали в своем примере более чистым способом, вы можете использовать вспомогательную функцию.
local function bind(t, k)
return function(...) return t[k](t, ...) end
end
Затем вы применяете его так.
anotherObject:aFunction(variable, bind(object, 'doStuff'))
Изменить: Я считаю, что решение вашей проблемы потребует привязки на каком-то уровне, не прибегая к модификации интерпретатора Lua или с помощью шага перевода кода. Это в основном потому, что функции в Lua не содержат никакой информации об их происхождении. I.e., таблицы не имеют собственных функций, которые они хранят.
Например, следующее является совершенно законным кодом Lua.
function Circle:area() -- function Circle.area(self)
-- ...
end
-- Evaluate the function in the "area" slot with Square as the self parameter.
Circle.area(Square)
Конечно, вы можете попробовать сдвиг парадигмы, но для этого может быть слишком поздно, если вы создаете целое приложение, основанное на идее привязки функций к таблице, из которой они были проиндексированы, как вы сказали, Поэтому я предлагаю следующее сумасшедшее решение.
local mt = {}
function mt:__index(k)
local v = self._slots[k]
if v == nil then
-- Ascend the inheritance tree.
-- This has to be done with rawget all the way up,
-- otherwise inherited functions would be repeatedly bound.
local p = self
repeat
p = rawget(p, '_parent')
if not p then break end
v = p._slots[k]
until v
end
if type(v) == 'function' then
-- Return a self-bound version of the function.
return function(...) return v(self, ...) end
end
return v
end
function mt:__newindex(k, v)
self._slots[k] = v
end
--- Demo & Tests ---
local function Object(parent)
local o = setmetatable({_slots = {}}, mt)
if parent then rawset(o, '_parent', parent) end
return o
end
local o1 = Object()
local o2 = Object(o1)
assert(o1.abc == nil, 'o1.abc should be nil')
o1.abc = 3
assert(o1.abc == 3, 'o1.abc should be 3')
assert(o2.abc == 3, 'o2.abc should be 3, inherited from o1')
o2.abc = 7
assert(o2.abc == 7, 'o2.abc should be 7, overriding o1')
assert(o1.abc == 3, 'o1.abc should be 3, unaffected by o2 setter')
function o1:test(bar)
return self.abc + bar
end
assert(type(o1.test) == 'function', 'o1.test should be a function')
assert(type(o2.test) == 'function', 'o2.test should be a function, inherited from o1')
assert(o1.test(5) == 8, 'o1.test(5) should return 3 + 5 = 8')
assert(o2.test(11) == 18, 'o2.test(11) should return 7 + 11 = 18')
function o2:test2(fn)
return self.abc + fn(7)
end
assert(o2.test2(o1.test) == 17, 'o2.test2(o1.test) should return 7 + (3 + 7) = 17')
o2.test3 = o1._slots.test -- proper function copying
assert(o2.test3(11) == 18, 'o2.test3(5) should return 7 + 11 = 18')
o2.abc = nil
assert(o2.abc == 3, 'o2.abc should be 3 again, inherited from o1 after clearing')
o2.abc = false
assert(o2.abc == false, 'o2.abc should be false, __index needs to differentiate between nil and false')
Этот метатет предоставит вам то, что вы хотите, с унаследованными и связанными функциями для загрузки. Вам просто нужно убедиться, что все таблицы, которые вы хотите следовать этому шаблону, также следуют методу создания объекта, показанному в примере кода.
Чтобы объяснить, каждая таблица, сделанная таким образом, имеет любое новое назначение, перенаправленное в подтаблицу _slots
, и любое новое извлечение проверило дерево наследования _parent
. Если тип значения равен function
, он возвращает новое замыкание с исходным self
, которое запустило привязку проверки к найденной функции.
Очевидно, вызов функции из одного из этих объектов с синтаксисом :
двоеточия будет глупой идеей, так как он будет оценивать до o.fn(o, o)
, и это, вероятно, не то, что вы хотите. Еще одно предостережение заключается в том, что копирование функций на эти объекты, из этих объектов, не будет работать должным образом. o1.newfn = o2.fn
поместит связанную функцию o2
в o1
, которая, в свою очередь, будет привязана к o1
. Конечным результатом будет что-то вроде o2.fn(o2, o1)
. Вам нужно будет скопировать функции из таблицы _slots
.
В заключение: Несмотря на то, что это работает, я бы не рекомендовал его в долгосрочной перспективе, так как это может смутить любого, кто использует Lua для работы с таблицами, индексацией и функциями, и будут накладные расходы. Возможно, вы сможете покончить с этим через memoizing закрытия, но я оставлю это решение до вас. Удачи!