Во-первых, для helloworld
ваш код работает:
/* file: hw.c
* on Debian/Ubuntu compile with:
* `gcc -I/usr/include/lua5.2 -fpic -shared -o hw.so hw.c`
*/
#include <lua.h>
#include <lauxlib.h>
struct SomethingWrapper {
void *object;
};
static int l_helloworld(lua_State *L) {
lua_pushliteral(L, "Hello World!");
return 1;
}
static luaL_Reg const some_funcs[] = {
{ "helloworld", l_helloworld },
{ NULL, NULL }
};
int push_Something(lua_State *L, void *object) {
struct SomethingWrapper *w = lua_newuserdata(L, sizeof(*w));
w->object = object;
luaL_setmetatable(L, "Something");
return 1;
}
int luaopen_hw(lua_State *L) {
luaL_newmetatable(L, "Something");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, some_funcs, 0);
lua_pop(L, 1);
push_Something(L, NULL);
return 1;
}
и тестовый скрипт:
-- file: hwtest.lua
local x = require("hw")
print(x.helloworld())
Выход:
Hello World!
Для доступа к свойствам на UserData вам нужно установите __index
на функцию вместо таблицы. Функция вызывается с двумя аргументами (userdata и ключ) всякий раз, когда вы пытаетесь получить доступ к полю в пользовательских данных, и вы можете запросить свой объект C и нажать нужный результат.
Это становится немного более сложным, если вы намерены одновременно поддерживать методы и свойства, но основной подход заключается в следующем: вы используете функцию как __index
metamethod. Эта функция имеет доступ к таблице методов (например, через upvalue или реестр и т. Д.) И пытается найти данный ключ в этой таблице. Если вы преуспеете, вы вернете это значение. Если вы ничего не придумали, вы сравните данный ключ с действительными именами свойств вашего объекта C и вернете соответствующие значения, если вы получите соответствие. (Если вы не получите матч, вы можете вернуть nil
или поднять ошибку - это зависит от вас.)
Вот многоразовая реализация этого подхода (извлеченная из moon toolkit):
static int moon_dispatch(lua_State* L) {
lua_CFunction pindex;
/* try method table first */
lua_pushvalue(L, 2); /* duplicate key */
lua_rawget(L, lua_upvalueindex(1));
if(!lua_isnil(L, -1))
return 1;
lua_pop(L, 1);
pindex = lua_tocfunction(L, lua_upvalueindex(2));
return pindex(L);
}
MOON_API void moon_propindex(lua_State* L, luaL_Reg const methods[],
lua_CFunction pindex, int nups) {
if(methods != NULL) {
luaL_checkstack(L, nups+2, "not enough stack space available");
lua_newtable(L);
for(; methods->func; ++methods) {
int i = 0;
for(i = 0; i < nups; ++i)
lua_pushvalue(L, -nups-1);
lua_pushcclosure(L, methods->func, nups);
lua_setfield(L, -2, methods->name);
}
if(pindex) {
lua_pushcfunction(L, pindex);
if(nups > 0) {
lua_insert(L, -nups-2);
lua_insert(L, -nups-2);
}
lua_pushcclosure(L, moon_dispatch, 2+nups);
} else if(nups > 0) {
lua_replace(L, -nups-1);
lua_pop(L, nups-1);
}
} else if(pindex) {
lua_pushcclosure(L, pindex, nups);
} else {
lua_pop(L, nups);
lua_pushnil(L);
}
}
Использование:
/* [ -nup, +1, e ] */
void moon_propindex(lua_State* L,
luaL_Reg const* methods,
lua_CFunction index,
int nup);
This function is used for creating an __index metafield. If index is NULL but methods is not, a table containing all the functions in methods is created and pushed to the top of the stack. If index is not NULL, but methods is, the index function pointer is simply pushed to the top of the stack. In case both are non NULL, a new C closure is created and pushed to the stack, which first tries to lookup a key in the methods table, and if unsuccessful then calls the original index function. If both are NULL, nil is pushed to the stack. If nup is non-zero, the given number of upvalues is popped from the top of the stack and made available to all registered functions. (In case index and methods are not NULL, the index function receives two additional upvalues at indices 1 and 2.) This function is used in the implementation of moon_defobject, but maybe it is useful to you independently.
Если вы попытаетесь сохранить произвольные значения Lua в UserData (как говорит название) - вы не можете. Но вы можете связать дополнительную таблицу (называемую «uservalue») с каждой пользовательской датой и сохранить там произвольные значения. Этот подход аналогичен описанному выше, но вместо того, чтобы сопоставлять с предопределенными именами свойств и напрямую обращаться к объекту C, вы сначала нажимаете таблицу uservalue (используя lua_getuservalue
), а затем просматриваете свое поле там.
Вы зарегистрировали/создали метатет перед использованием 'push_Something' правильно? –
Правильно, метатабель был создан первым – 010110110101