Previous Entry Share Next Entry
ООП в Lua: Реализация класса
and_cesbo

Сейчас занимаюсь проработкой выделения модулей Астры в отдельные Lua-объекты.
В текущей версии lua используется только для передачи всех параметров в ядро астры (функция mod.init разгребает таблицу описывающая дерево модулей и создаёт экземпляры модулей).
Объектная модель позволит более тесно взаимодействовать с модулями Астры из Lua-скриптов.
В Lua классов как бы нет, но есть мета-таблицы позволяющие реализовать подобие класса.


Реализация класса на Lua

Класс удобней объявлять через вспомогательную функцию:
function class()
local c = {}
c.__index = c
c.__gc = function()
if c.destroy then
c.destroy()
end
end
local mt = {}
mt.__call = function(_, ...)
self = setmetatable({}, c)
if c.init then
c.init(self, ...)
end
return self
end
return setmetatable(c, mt)
end

Реализация класса будет выглядеть так:
local simple = class()
 
function simple:__tostring()
return "Lua module: simple [" .. self.name .. "]"
end
 
function simple:init(name)
self.name = name
print("simple:init()")
end
 
function simple:destroy()
print("simple:destroy()")
end

Все функции опциональны.
:init - выполняется при инициализации класса
:destroy - при удалении класса сборщиком мусора
:__tostring - преобразование объекта в текст (например в функции print)

Использование класса:
local obj = simple("TEST")
print(obj)
obj = nil
collectgarbage()


Реализация класса на Си

static const char __module_name[] = "simple";
 
#define MODULE_INSTANCE_INIT(_L)
(module_data_t *)lua_touserdata(_L, -1)
#define MODULE_INSTANCE(_L)
(module_data_t *)luaL_checkudata(_L, 1, __module_name)
 
/* module functions */
 
static void module_init(lua_State *L)
{
module_data_t *mod = MODULE_INSTANCE_INIT(L);
}
 
static void module_destroy(lua_State *L)
{
module_data_t *mod = MODULE_INSTANCE(L);
}
 
/* required */
 
static int __module_new(lua_State *L)
{
module_data_t *mod = lua_newuserdata(L, sizeof(module_data_t));
memset(mod, 0, sizeof(module_data_t));
mod->__name = __module_name;
lua_getmetatable(L, 1);
lua_setmetatable(L, -2);
module_init(L);
return 1;
}
 
static int __module_delete(lua_State *L)
{
module_destroy(L);
return 0;
}
 
static int __module_tostring(lua_State *L)
{
module_data_t *mod = MODULE_INSTANCE(L);
lua_pushfstring(L, "module: %s [%p]", mod->__name, (void *)mod);
return 1;
}
 
int LUA_API luaopen_simple(lua_State *L)
{
static const luaL_Reg meta_methods[] =
{
{ "__gc", __module_delete },
{ "__tostring", __module_tostring },
{ "__call", __module_new },
{ NULL, NULL }
};
static const luaL_Reg module_methods[] = {
{ NULL, NULL }
};
lua_newtable(L);
const int module_table = lua_gettop(L);
luaL_newmetatable(L, __module_name);
const int meta_table = lua_gettop(L);
luaL_setfuncs(L, meta_methods, 0);
luaL_newlib(L, module_methods);
lua_setfield(L, meta_table, "__index");
luaL_newlib(L, meta_methods);
lua_setfield(L, meta_table, "__metatable");
lua_setmetatable(L, module_table);
lua_setglobal(L, __module_name);
return 1;
}

Для удобства подготовил набор дефайнов. Все дополнительные функции класса объявляются в массиве module_methods.


?

Log in

No account? Create an account