Сохранить наследуемый член таблицы в дочерний класс, если __index вызывается объектом дочернего класса
Моя цель состоит в том, чтобы иметь стандартный способ создания классов с полноразмерным множественным наследованием и возможностью не только наследовать другие классы, но и экземпляры самих себя через new()
-конструктор. Если я вызываю отсутствующее значение из класса или из его объекта, и это значение является функцией, я хотел бы сохранить его в классе для последующего использования, но не в объекте / экземпляре (проблемы с производительностью при реализации той же функции в массовом количество предметов класса).
На данный момент я использую createClass(...)
-функция, очень похожая на ту, которая упоминается в официальной серии учебников ( http://www.lua.org/pil/16.3.html), для создания классов, которые наследуются практически от любого числа родительских классов:
-- look up for k in list of tables plist
local function search (k, plist)
for i=1, #plist do
local v = plist[i][k] -- try i-th superclass
if v then return v end
end
end
local function createClass (...)
local args = {...};
local c = {};
-- search all provided parent classes for variables/functions to inherit and include them
-- could be done without including them (deeply nested inheritance might be an issue this way
-- due to repeated search calls for each use of an inherited function)
setmetatable(c, {__index = function (t, k)
local v = search(k, args);
t[k] = v;
print(t, " ...looking for... ", k, v);
return v;
end})
return c;
end
Он передает индекс-метаметод недавно созданному классу, который ищет во всех родителях указанный отсутствующий ключ и сохраняет его для последующего использования в вызывающем классе. Это работает как намерение, даже при поиске огромной иерархии вложенного наследования. Теперь давайте введем простой класс с базовым конструктором:
local P = {};
local MyClass = P;
function P.new ()
local self = {};
local priv = {};
setmetatable(self, {__index = function (t, k)
-- shouldn't this invoke __index-metamethod of P because P does not already have k
-- at this stage of the program?
local v = P[k];
print(t, " ...looking for ... ", k, v);
if(type(v) == "function") then
-- ??? maybe do somethine else here to enforce __index of class P
else
t[k] = v;
end
return v;
end});
self.testSelf = function () print("testSelf") end;
priv.testPriv = "testPriv!";
function self.accessPriv ()
return priv;
end
return self;
end
function P.TEST ()
print("calling TEST");
end
Если мы вызовем эту реализацию наследования и класса с помощью следующего кода, то мы увидим, что __index
-метаметод класса не вызывается при создании нового экземпляра класса (сравните адреса выходных таблиц), даже если __index
-метаметод объекта запрашивает отсутствующее значение / функцию из его (родительского) класса, который не имеет такого значения / функции на данный момент. По-видимому, это описание не вызывает __index
-метаметод самого класса, который меня смущает. Я бы предположил, что он всегда вызывается, если запрашивается пропущенное значение класса / таблицы, независимо от того, из какой части скрипта.
- Почему
__index
-метаметод изMyClass
не вызывается в данном примере? - И как я могу сделать это (делая как можно меньше изменений в коде)?
Ваши предложения приветствуются!
1 ответ
Я нашел ответ, не понимая его полностью. Оказывается, при вызове конструктора класса new
Требуется передать ему сам класс. Таким образом, я могу напрямую манипулировать переменной, которая представляет класс. До сих пор остается путаница в отношении того, почему я могу наследовать от класса и его родителей экземпляр / объект класса, но не могу получить доступ к классу для какой-либо другой операции в объектах. __index
-metamethod.
Это определение класса, наконец, делает свою работу:
local P = {};
local MyClass = P;
-- must pass class itself while creating new object of it (don't know why...)
function P:new ()
local pub = {};
local priv = {};
setmetatable(pub, {__index = function (t, k)
local v = P[k];
-- store functions into the class for later use (less duplicates)
-- and all other inherited variables into the objects itself
if (type(v) == "function")
self[k] = v;
else
t[k] = v;
end
return v;
end});
pub.testSelf = function () print("testSelf") end;
priv.testPriv = "testPriv!";
function pub.accessPriv ()
return priv;
end
return pub;
end
function P.TEST ()
print("calling TEST");
end