假设我在Lua中将许多不同的函数名注册到C中的相同函数。现在,每次调用我的C函数时,有没有办法确定调用了哪个函数名?
例如:
int runCommand(lua_State *lua)
{
const char *name = // getFunctionName(lua) ? how would I do this part
for(int i = 0; i < functions.size; i++)
if(functions[i].name == name)
functions[i].Call()
}
int main()
{
...
lua_register(lua, "delay", runCommand);
lua_register(lua, "execute", runCommand);
lua_register(lua, "loadPlugin", runCommand);
lua_register(lua, "loadModule", runCommand);
lua_register(lua, "delay", runCommand);
}
那么,我如何获得所谓的函数名称呢?
答案 0 :(得分:11)
攻击您的问题的另一种方法是使用upvalues。基本上,您使用以下函数注册C函数,而不是lua_register
:
void my_lua_register(lua_State *L, const char *name, lua_CFunction f)
{
lua_pushstring(L, name);
lua_pushcclosure(L, f, 1);
lua_setglobal(L, name);
}
然后,getFunctionName是直接的
const char* getFunctionName(lua_State* L)
{
return lua_tostring(L, lua_upvalueindex(1));
}
那就是说,你想做的事似乎很可疑 - 你想要达到什么目的?问题中发布的runCommand
函数看起来像是一种非常低效的方式来做Lua为你做的事情。
答案 1 :(得分:2)
您可以使用lua_getinfo:http://pgl.yoyo.org/luai/i/lua_getinfo
这可能有效:
const char* lua_getcurrentfunction(lua_State* L) {
lua_Debug ar;
lua_getstack(L, 1, &ar);
lua_getinfo(L, "f", &ar);
return ar.name;
}
有一点需要注意:
name:给定函数的合理名称。因为Lua中的函数是一等值,所以它们没有固定的名称:某些函数可能是多个全局变量的值,而其他函数可能只存储在表字段中。 lua_getinfo函数检查函数的调用方式以查找合适的名称。如果找不到名称,则将name设置为NULL。
答案 2 :(得分:2)
另一种解决方案是为Lua环境表注册metatable,该表实现__index
元方法以调度这些函数调用。
答案 3 :(得分:0)
不幸的是,这是不可能的 - 除此之外,因为Lua中的函数实际上根本没有名字。 (考虑:(loadstring("a=1"))()
正在执行从loadstring
返回的无名函数。)
答案 4 :(得分:0)
如果您愿意捏造所有未知函数执行,您可以使用setmetatable和currying来玩游戏:
-- This function would not be in lua in your example, -- you'd be doing lua_register( lua, "runCommandNamed", runCommandNamed ) -- and writing a runCommandNamed in C. function runCommandNamed( cmd, ... ) print( "running command", cmd, "with arguments", ... ) end -- The rest would be somewhere in lua-land: local utilMetaTable = { __index = function ( t, key ) return function( ... ) -- mmm, curry runCommandNamed( key, ... ) end end } _util = {} setmetatable( _util, utilMetaTable ) -- prints "running command CommandOne with arguments arg1 arg2 arg3" _util.CommandOne( "arg1", "arg2", "arg3" ) -- prints "running command CommandTwo with arguments argA argB" _util.CommandTwo( "argA", "argB" )
在这个例子中,我只是在_util
下而不是在全局表中添加了未知的执行。