Как создать объект класса в Lua-C API 5.2?
Я обертываю функцию C с помощью Lua, используя Lua-C API для Lua 5.2:
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
int foo_gc();
int foo_index();
int foo_newindex();
int foo_dosomething();
int foo_new();
struct foo {
int x;
};
static const luaL_Reg _meta[] = {
{"__gc", foo_gc},
{"__index", foo_index},
{"__newindex", foo_newindex},
{ NULL, NULL }
};
static const luaL_Reg _methods[] = {
{"new", foo_new},
{"dosomething", foo_dosomething},
{ NULL, NULL }
};
int foo_gc(lua_State* L) {
printf("## __gc\n");
return 0;
}
int foo_newindex(lua_State* L) {
printf("## __newindex\n");
return 0;
}
int foo_index(lua_State* L) {
printf("## __index\n");
return 0;
}
int foo_dosomething(lua_State* L) {
printf("## dosomething\n");
return 0;
}
int foo_new(lua_State* L) {
printf("## new\n");
lua_newuserdata(L,sizeof(Foo));
luaL_getmetatable(L, "Foo");
lua_setmetatable(L, -2);
return 1;
}
void register_foo_class(lua_State* L) {
luaL_newlib(L, _methods);
luaL_newmetatable(L, "Foo");
luaL_setfuncs(L, _meta, 0);
lua_setmetatable(L, -2);
lua_setglobal(L, "Foo");
}
Когда я запускаю этот Lua:
local foo = Foo.new()
foo:dosomething()
... я вижу этот вывод (с ошибкой):
## new
## __index
Failed to run script: script.lua:2: attempt to call method 'dosomething' (a nil value)
Что я делаю не так?
Ответы
Ответ 1
Хорошо, получил это работает. Мне пришлось добавить __index
и __metatable
в Foo
новые метатаблицы, как показано ниже:
void register_foo_class(lua_State* L) {
int lib_id, meta_id;
/* newclass = {} */
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
/* metatable = {} */
luaL_newmetatable(L, "Foo");
meta_id = lua_gettop(L);
luaL_setfuncs(L, _meta, 0);
/* metatable.__index = _methods */
luaL_newlib(L, _methods);
lua_setfield(L, meta_id, "__index");
/* metatable.__metatable = _meta */
luaL_newlib(L, _meta);
lua_setfield(L, meta_id, "__metatable");
/* class.__metatable = metatable */
lua_setmetatable(L, lib_id);
/* _G["Foo"] = newclass */
lua_setglobal(L, "Foo");
}
Ответ 2
Я попытался ответить на ваше решение, но, видимо, у меня пока нет такой репутации, поэтому здесь идет отдельный ответ.
Ваше решение довольно хорошо, но оно не позволяет делать что-то, что я хотел бы сделать: иметь как "массивный" доступ к объекту, так и иметь на нем функции. Посмотрите на этот код Lua:
Foo = {}
mt = {
__index = function(table, key)
print("Accessing array index ", tostring(key), "\n")
return 42
end
}
setmetatable(Foo, mt)
Foo.bar = function()
return 43
end
print(tostring(Foo[13]), "\n")
print(tostring(Foo.bar()), "\n")
--[[
Output:
Accessing array index 13
42
43
]]--
Регистрация класса с использованием вашего решения, похоже, не позволяет этого, поскольку запись __index
перезаписывается.
Возможно, нет смысла иметь доступ к массиву и доступ к функциям в классе, но для простоты (предлагая одну функцию C для регистрации обоих типов классов), я бы хотел использовать тот же код везде. Кто-нибудь знает, как это ограничение можно обойти, так что я могу создать класс из C, который имеет как функцию Foo.bar(), так и Foo [13]?