首先,对于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() )
输出是:
你好世界!
要访问用户数据的属性,您需要设置__index
为函数而不是表。每当您尝试访问用户数据上的字段时,都会使用两个参数(用户数据和键)调用该函数,并且您可以查询您的 C 对象并推送所需的结果。
如果您打算同时支持方法和属性,它会变得有点复杂,但基本方法如下:您使用函数作为__index
元方法。该函数可以访问方法表(例如,通过上值或注册表等)并尝试在该表中查找给定的键。如果成功,则返回该值。如果什么都没有,则将给定的键与 C 对象的有效属性名称进行比较,如果匹配,则返回相应的值。(如果你没有得到匹配,你可以返回nil
或引发错误——这取决于你。)
这是该方法的可重用实现(摘自月球工具包):
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 );
此函数用于创建 __index 元字段。如果 index 为 NULL 但 methods 不是,则创建一个包含方法中所有函数的表并将其推送到堆栈顶部。如果 index 不是 NULL,但 methods 是,则 index 函数指针被简单地推到堆栈的顶部。如果两者都不是 NULL,则创建一个新的 C 闭包并将其推送到堆栈,它首先尝试在方法表中查找一个键,如果不成功则调用原始索引函数。如果两者都为 NULL,则将 nil 压入堆栈。如果 nup 不为零,则从堆栈顶部弹出给定数量的上值,并可供所有注册函数使用。(如果 index 和 methods 不为 NULL,则 index 函数在索引 1 和 2 处接收两个额外的上值。)此函数用于 moon_defobject 的实现,
如果你尝试在用户数据中存储任意 Lua 值(如标题所示)——你不能。但是您可以将一个额外的表(称为“uservalue”)与每个用户数据相关联,并在那里存储任意值。该方法类似于上面的方法,但不是与预定义的属性名称匹配并直接访问 C 对象,而是首先推送 uservalue 表(使用lua_getuservalue
),然后在那里查找您的字段。