问题
好的,让我们来看看这个函数和堆栈。
luaL_newmetatable(L, libname);
好的,堆栈现在包含来自元表注册表的表:
-1: table<libname>{possibly empty}
下一步:
lua_newtable(L);
堆栈现在包含:
-1: table<new>{empty}
-2: table<libname>{possibly empty}
下一步:
luaL_setfuncs(L,l,0);
不改变堆栈。但它确实在表中设置了一堆函数。
-1: table<new>{bunch of functions}
-2: table<libname>{possibly empty}
下一步:
lua_pushvalue(L,-1);
这会复制堆栈顶部的值。那是我们的表,里面有一堆函数:
-1: table<new>{bunch of functions}
-2: table<new>{bunch of functions}
-3: table<libname>{possibly empty}
下一步:
if(sublibname != NULL)
{
lua_newtable(L);
这会在堆栈上创建一个空的新表:
-1: table<new2>
-2: table<new>{bunch of functions}
-3: table<new>{bunch of functions}
-4: table<libname>{possibly empty}
下一步:
lua_setfield(L, -2, sublibname);
这个函数,as stated in the documentation,在给定的表键名处设置一个值到表中。值是栈顶的值,但它放入的表是索引。
所以你刚刚这样做了:
-1: table<new>{bunch of functions, sublibname=table<new2>}
-2: table<new>{bunch of functions, sublibname=table<new2>}
-3: table<libname>{possibly empty}
我很确定这不是你想要的。当我们继续时,我会讨论如何解决这个问题。
下一步:
}
lua_setglobal(L, libname);
这会获取栈顶并将其粘在全局表中,将其从栈顶弹出。
所以堆栈现在看起来像这样:
-1: table<new>{bunch of functions, sublibname=table<new2>{empty}}
-2: table<libname>{possibly empty}
全局表现在有:
_G[libname] = table<new>{bunch of functions, sublibname=table<new2>{empty}}
因此,您不仅使堆栈不平衡(推送多于弹出),而且您没有得到您真正想要的东西。另外,注册表中的元表包含...什么都没有。
解决方案
所以让我们解决这个问题。让我们好好地去做吧。
您尝试做的几乎所有事情都是错误的。首先,做子表的唯一原因是这样的代码可以工作:
myregister(execContext, "dog", "beagle", fidofuncModule);
myregister(execContext, "dog", "dane", danefuncModule);
这样,您可以致电dog.beagle 和dog.dane。好吧,为此,myregister 必须检查全局表以查看是否已经存在 dog 表。如果有,它需要在其中存储它的东西,如果没有,它需要创建它。所以你的整个算法有点坏了。
另外,大概你希望dog.beagle 和dog.dane 都有自己的fetch 函数。好吧,注册表只有一个地方可以存放 dog 表,所以如果您只使用 libname 进行 luaL_newmetatable 调用,他们就会互相踩踏。
我会这样解决它。我不知道这是否适用于你正在做的事情,但这就是我要做的。
首先,忘记整个newmetatable废话;我们总是根据新表格工作。所以我们将创建内表并在其上设置函数:
lua_newtable(L);
luaL_setfuncs(L,l,0);
所以堆栈看起来像:
-1: table<new>{bunch of functions}
下一步,如果我们没有子库名称,那么我们应该直接将其设置到libname下的全局变量中并返回:
if(!sublibname)
{
lua_setglobal(L, libname);
return;
}
这将从堆栈中弹出一个值并将其设置在该位置。
由于我们确实有一个子库名称,因此我们需要将此表存储在主表中。如果_G[libname] 中已经有一个表,那么我们得到那个表。否则,我们创建一个新表并将其粘贴到_G[libname]。
lua_getglobal(L, libname);
if(lua_isnil(L, -1))
{
/*No table. Must create it and put it into the global*/
lua_newtable(L);
lua_pushvalue(L, -1); /*duplicate it on the stack*/
lua_setglobal(L, libname); /*pushes duplicate*/
}
此时,我们的堆栈包含:
-1: table<libname>{possibly empty}
-2: table<new>{bunch of functions}
然后我们将创建的表粘贴到该表中,使用sublibname 作为字段:
lua_pushvalue(L, -2); /*duplicates our created table*/
lua_setfield(L, -2, sublibname);
现在堆栈包含:
-1: table<libname>{stuff, sublibname=table<new>{bunch of functions}}
-2: table<new>{bunch of functions}
由于表已经在全局表中(我们要么从那里得到它,要么在创建它时将它存储在那里),我们就完成了。所以清理堆栈:
lua_pop(L, 2); /*balance the stack. Remove our junk from it*/