获取正确的Lua元方法来调用(C-api)
我正在使用[实际学习使用] Lua C api。我是Lua的新手,所以如果我有一些术语不正确,我会很感激,并希望对它有所更正。获取正确的Lua元方法来调用(C-api)
我有一个空的全局表G,我在init的某个时候使用lua_setglobal创建了这个表。 G的__index指向一个C函数,我相信它被称为metamethod。当被调用时,该函数会创建一个新的lightuserdata项目,并将其插入到G全局表格中。
因此,如果我的理解是正确的,G.foo将导致调用G的__index元方法,foo将由它创建并添加到G.未来对G.foo的调用将不再需要调用元方法因为它会发现foo存在于G.
现在,当创建foo时,我通过将其__index设置为一个C函数数组,将一个metatable与新创建的lightuserdata(foo)相关联,其中最着名的是'set '和'get'。的想法是,只要富:get()方法被调用时,Foo的元表,应抬头向调用C函数来获得它的值等
这里的(正常)的行为我看到:
-
从lua文件中调用G.foo。
这会按预期使用G的metamethod创建foo。
-
然后,调用G.foo:get()
由于foo是已经G(之前的步骤)的一部分,G的元方法不被调用,如所预期。相反,将检查foo的metatable,并调用与'get'对应的C函数。这也如预期的那样,并且正是我希望它工作的方式。
但是,如果我这样做:
-
调用G.foo:get()的情况下直接调用第一G.foo
然后,它调用G公司的元方法两次,一次为foo(预计)和一次'get'(不是预期的)。我不希望被'G'__index metamethod处理。它基本上试图创建一个名为'get'的新lightuserdata(就像它为'foo'所做的一样)等等,这不是我想要做的。我想要查看新创建的foo的metatable,以便为foo调用适当的'get'C函数。
为了使问题最明显,我简化了我的用例,所以我希望它足够容易理解。此外,如果你能指出我的任何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;
}
给予代码为你描述它,问题是lua_metaMethod
(BTW:这是一个坏想法来命名你的功能lua_
。这是一个为Lua API函数保留的前缀)。
元法的返回值将为返回给用户的。因此,如果用户说G.foo
,那么将返回G
的元方法的返回值__index
metamethod。
lua_metaMethod
返回什么?它只返回1个返回值。由于传递给函数的参数是堆栈中的第一个参数,它将返回第一个参数。元方法的第一个参数始终是metamethod被调用的表。在你的情况下,这个表格是存储在G
中的表格。因此,G.foo
将返回G
。因此,G.foo:get()
相当于G:get()
(虽然第一个版本确实有一个额外的metamethod调用)。我猜这不是你想要的;)
它应该返回的是刚刚存储在G["foo"]
中的light userdata。
请考虑使用此代码。
static int lua_metaMethod(lua_State *luaVM)
{
//We won't use this, so only do this if you need the string.
const char *name = lua_tostring(luaVM, 2);
// I then lookup 'fooData', which is a pointer to data associated with foo that I want to add to G.
//No need to get G. We already have it: the first parameter.
lua_pushlightuserdata(luaVM, (void*) fooData); //Stack: table, key, userdata
lua_createtable(luaVM, 0, 0); //Stack: table, key, userdata, {}
lua_createtable(luaVM, 0, 0); //Stack: table, key, userdata, {}, {}
luaL_register(luaVM, NULL, lua_methods); // Trying to make sure foo:get() calls one of these, etc.
lua_setfield(luaVM, -2, "__index"); //Stack: table, key, userdata, {}
lua_setmetatable(luaVM, -2); //Stack: table, key, userdata
//Stack now contains: table, key, userdata.
lua_insert(luaVM, 2); //Stack: table, userdata, key
lua_pushvalue(luaVM, -2); //Stack: table, userdata, key, userdata
lua_rawset(luaVM, 1); //Use rawset because table has a metatable. It's probably best not to invoke it.
//Stack now contains: table, userdata.
lua_insert(luaVM, 1); //Stack: userdata, table.
return 1; //Return just the userdata. `table` will be discarded.
}
Lua是一个正确的名称。这意味着首字母大写。所以它是Lua,而不是Lua或LUA。 – 2012-03-22 02:44:47
添加了一些代码到我原来的帖子来演示。看起来我的确有术语错误,对不起! – Varun 2012-03-22 03:09:24