C++11 在单个Lua状态下使用多个脚本并使用_ENV
我目前正在学习如何使用Lua C API,虽然我已经成功地在C/C++和Lua之间绑定函数,但我有几个问题:C++11 在单个Lua状态下使用多个脚本并使用_ENV,c++11,lua,lua-api,lua-c++-connection,C++11,Lua,Lua Api,Lua C++ Connection,我目前正在学习如何使用Lua C API,虽然我已经成功地在C/C++和Lua之间绑定函数,但我有几个问题: 将多个脚本加载到一个lua\u状态,这是一个好主意吗?有没有关闭特定区块的方法?如果脚本不再使用,如何在保留所有其他内容的同时将其从lua\u状态中清除 使用可能对函数/全局变量使用相同名称的脚本的最佳方式是什么?如果我加载所有的定义,新的定义将覆盖旧的定义 在线阅读后,我想我需要分离每个加载的块 进入不同的环境。我设想这项工作的方式是 加载块时,我会为其指定一个唯一的环境名称 需要使用
lua\u状态
,这是一个好主意吗?有没有关闭特定区块的方法?如果脚本不再使用,如何在保留所有其他内容的同时将其从lua\u状态中清除
区块生成的任何内容(全局或在外部某处有引用的局部变量)将继续存在 如何在保留所有其他内容的同时将其从lua_状态中清除 这取决于你如何看待这一块。它只是一组函数,还是用自己的状态表示某个实体。若您不创建全局函数和变量,那个么在单独的脚本文件中定义的所有内容都将是chunk的本地内容,并且在并没有对chunk的引用时将被删除 使用可能对函数/全局变量使用相同名称的脚本的最佳方式是什么 考虑重写代码。不要创建任何globals,除非明确要求它与程序的其他部分建立通信。将变量设置为本地变量(由chunk拥有),或将其存储在chunk将作为新对象返回的表/闭包中-chunk可能是生成新对象的工厂,而不是jush脚本。
此外,Lua使用本地变量运行得更快 我设想这项工作的方式是,每次加载块时,我都为其指定一个唯一的环境名称
如果脚本来自外部(由用户编写或从其他外部源接收),则应该这样做。沙箱很酷,但如果块是你的内部材料,就没有必要使用沙箱。考虑改写无全局代码的代码。如果区块生成其他对象,则返回一些对象(api表或闭包)——您可以多次调用该区块而无需重新加载它。或者保存一个全局模块接口,如果chunk表示类似Lua的模块。如果您没有很好地组织代码,那么您将被迫使用单独的环境,并且您必须为每个脚本准备新的环境,复制基本内容,如print/pairs/string/等。在运行时,您将有许多中断,直到您发现新环境中缺少了更多内容,诸如此类。在多翻了几遍之后,我找到了我认为是我一直在寻找的解决方案。我不确定这是否是正确/最好的方法,但它在我的基本测试用例中起作用@雅各布对这个问题的回答帮助很大 test1.lua
x = 1
function hi()
print("hi1");
print(x);
end
hi()
test2.lua
x =2
function hi()
print("hi2");
print(x);
end
hi()
main.cpp
int main(void)
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
char* file1 = "Rooms/test1.lua";
char* file2 = "Rooms/test2.lua";
//We load the file
luaL_loadfile(L, file1);
//Create _ENV tables
lua_newtable(L);
//Create metatable
lua_newtable(L);
//Get the global table
lua_getglobal(L, "_G");
lua_setfield(L, -2, "__index");
//Set global as the metatable
lua_setmetatable(L, -2);
//Push to registry with a unique name.
//I feel like these 2 steps could be merged or replaced but I'm not sure how
lua_setfield(L, LUA_REGISTRYINDEX, "test1");
//Retrieve it.
lua_getfield(L, LUA_REGISTRYINDEX, "test1");
//Set the upvalue (_ENV)
lua_setupvalue(L, 1, 1);
//Run chunks
lua_pcall(L, 0, LUA_MULTRET, 0);
//Repeat
luaL_loadfile(L, file2);
lua_newtable(L);
lua_newtable(L);
lua_getglobal(L, "_G");
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
lua_setfield(L, LUA_REGISTRYINDEX, "test2");
lua_getfield(L, LUA_REGISTRYINDEX, "test2");
lua_setupvalue(L, 1, 1);
lua_pcall(L, 0, LUA_MULTRET, 0);
//Retrieve the table containing the functions of the chunk
lua_getfield(L, LUA_REGISTRYINDEX, "test1");
//Get the function we want to call
lua_getfield(L, -1, "hi");
//Call it
lua_call(L, 0, 0);
//Repeat
lua_getfield(L, LUA_REGISTRYINDEX, "test2");
lua_getfield(L, -1, "hi");
lua_call(L, 0, 0);
lua_getfield(L, LUA_REGISTRYINDEX, "test2");
lua_getfield(L, -1, "hi");
lua_call(L, 0, 0);
lua_getfield(L, LUA_REGISTRYINDEX, "test1");
lua_getfield(L, -1, "hi");
lua_call(L, 0, 0);
lua_close(L);
}
输出:
hi1
1
hi2
2
hi1
1
hi2
2
hi2
2
hi1
1
如果这意味着什么的话,我正在Visual Studio 2013中使用Lua 5.3.2
这个基本测试用例可以根据需要工作。我将继续测试,看看是否出现任何问题/改进。如果有人认为我可以改进这段代码,或者发现一些明显的错误,请留下评论。您应该将每个脚本视为不同的模块。 就像您的代码中有超过1个“require”一样 “加载的块”应返回将全局存储的表
加载大量全局变量不是一个好主意,在您添加更多模块后,这可能会导致不好的结果。谢谢您的回答!我想我应该在我最初的帖子中提到,我的最终目标是沙箱,或者至少运行不是我写的脚本。我会有必须遵循的一般准则,但我也希望用户和贡献者拥有自由。这些准则可能要求用户在其所有脚本中都有一个全局定义的表a。这意味着我需要使用环境,因为它们在任何时候都可能有任意数量的脚本处于该状态,但我不知道如何从C/C++中执行,这不是我在下面的回答中所做的吗?_ENV不是一个表吗?我真的很喜欢这个答案,并且正在使用类似的东西。如何在同一文件中的函数之间共享内存?理想情况下,我希望在函数之外的文件中创建变量,然后为文件中的函数提供可修改的访问权限;到目前为止,它们有访问权限,但是,它们的修改不会持续超过函数本身。是否可以在文件中声明变量?在我的示例中,变量x对于所有函数都是全局的,更改应该保持不变。你能给我举个例子吗?当然。“本地y=0;函数First();y=12;z=21;end;函数Second();print(y)-12;print(z)-nil;end”对不起,注释中没有换行符,对吗?所以,我有两个函数,我有一个“文件级”变量Y,可以被函数访问(闭包,对吗?),然后我在第一个函数中创建一个变量,但是调用第二个,我没有看到变量。第二个()在同一个文件中吗?是的,它们都在同一个文件中。其思想是将file1视为一个“类”,其中在函数之外定义的任何内容都应该是一个成员变量(我认为在您创建的_ENV中,是吗?),然后函数就是成员函数。因此,在C++中,我将调用整个文件,使之具有