获取正确的Lua元方法被调用(C API)
我正在使用[实际学习使用]Lua C API。我对Lua很新,如果我有一些术语不正确,我很抱歉,并希望得到任何更正。
我有一个空的全局表G,我在某个初始化点上使用lua_setglobal创建。 G的__index指向一个C函数,我相信这被称为元方法。当调用时,此函数会创建一个新的lightuserdata项,并将其插入G全局表中。
因此,如果我理解正确,G.foo将导致调用G的__index元方法,并且foo将由它创建并添加到G中。由于它会在G中找到foo存在,因此对G.foo的未来调用将不再需要调用元方法。
现在,当创建foo时,我通过将其__index设置为包含C函数数组的元表来关联新创建的lightuserdata(foo),其中包含“set”和“get”等最重要的函数。的想法是,每当foo:get()被调用时,应查找foo的元表以调用C函数以获取其值,等等。
这是我看到的(正常)行为:
从lua文件调用G.foo。
这将使用G的元方法如预期创建foo。
然后,调用G.foo:get()
由于foo已经是G的一部分(上一个步骤),因此不会调用G的元方法,如预期的那样。相反,将检查foo的元表并调用与“get”对应的C函数。这也是预期的,并且正是我希望它工作。
但是,如果我这样做:
直接调用G.foo:get(),而没有先调用G.foo
然后,它将两次调用G的元方法,一次为foo(预期),一次为“get”(未预期)。我不希望'get'被处理为G的__index元方法。它基本上尝试创建一个名为“get”的新lightuserdata(就像它为“foo”一样),等等,这不是我想要做的。我希望查找新创建的foo的元表,以便为foo调用正确的C函数“get”。
为了使问题更加明显,我简化了我的用例,因此希望它足够清楚。此外,如果您可以指出任何lua文档或功能参考,这将有助于我理解为什么会发生这种情况。
编辑: 添加一些代码,其中包含相关部分以演示我正在做的事情:
static void init()
{
lua_newtable( luaVM );
lua_createtable( luaVM, 0, 0 );
lua_pushcfunction( luaVM, lua_metaMethod );
lua_setfield( luaVM, -2, "__index" );
lua_setmetatable( luaVM, -2 );
lua_setglobal( luaVM, "G" );
}
static const luaL_reg lua_methods[] =
{
{ "set", lua_set },
{ "get", lua_get },
{0, 0}
};
static int lua_metaMethod( lua_State *luaVM )
{
// I get "foo" by using lua_tostring( luaVM, 2 ), and store that in 'name'.
// I then lookup 'fooData', which is a pointer to data associated with foo that I want to add to G.
lua_getglobal( "G" );
lua_pushlightuserdata( luaVM, ( void* ) fooData );
lua_createtable( luaVM, 0, 0 );
lua_createtable( luaVM, 0, 0 );
luaL_register( luaVM, NULL, lua_methods ); // Trying to make sure foo:get() calls one of these, etc.
lua_setfield( luaVM, -2, "__index" );
lua_setmetatable( luaVM, -2 );
lua_setfield( luaVM, -2, name );
return 1;
}
原文链接 https://stackoverflow.com/questions/9815658
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
根据你描述的代码,问题出现在
lua_metaMethod
中(顺便说一句:使用lua_
命名函数不是个好主意。这个前缀已经被保留给 Lua API 函数了)。__index
元方法的返回值将会被返回给用户。所以如果用户调用了G.foo
,那么就会返回G
的__index
元方法的返回值。lua_metaMethod
返回了一个返回值。因为传递给函数的参数是栈上的第一个,所以它将返回第一个参数。__index
元方法的第一个参数总是元方法所在的表。在你的代码中,这个表就是存储在G
中的表。因此,
G.foo
将返回 **G
**。因此,G.foo:get()
等同于G:get()
(尽管第一种方式多了一个元方法调用)。我猜这不是你想要的 ;)它应该返回刚存储在
G["foo"]
中的轻量用户数据。考虑使用这段代码代替:
static int lua_metaMethod( lua_State *luaVM ) { //这里我们不用这个值,所以只在需要字符串时才获取。 const char *name = lua_tostring(luaVM, 2); // 我们查找 'fooData',这是一个指针,指向与 foo 相关的数据,我们要将其添加到 G 中。 //我们不需要再次获取 G。我们已经有了它:第一个参数。 lua_pushlightuserdata( luaVM, ( void* ) fooData ); //栈:table, key, userdata lua_createtable( luaVM, 0, 0 ); //栈:table, key, userdata, {} lua_createtable( luaVM, 0, 0 ); //栈:table, key, userdata, {}, {} luaL_register( luaVM, NULL, lua_methods ); // 确保 foo:get() 调用了这些函数之一等等。 lua_setfield( luaVM, -2, "__index" ); //栈:table, key, userdata, {} lua_setmetatable( luaVM, -2 ); //栈:table, key, userdata //栈现在包含:table, key, userdata。 lua_insert(luaVM, 2); //栈:table, userdata, key lua_pushvalue(luaVM, -2); //栈:table, userdata, key, userdata lua_rawset(luaVM, 1); //使用 rawset 是因为表有元表。最好不要调用它。 //栈现在包含:table, userdata。 lua_insert(luaVM, 1); //栈:userdata, table。 return 1; //只返回 userdata。`table` 将被丢弃。 }