在单个 Lua 状态中运行多个脚本并使用 _ENV
2016-4-1 20:26:3
收藏:0
阅读:110
评论:3
我目前正在学习使用 Lua C API,虽然我已经成功地在 C/C++ 和 Lua 之间绑定了函数,但是我有几个问题:
将多个脚本加载到单个
lua_State中是否是一个好主意?是否有一种关闭特定块的方法?如果脚本不再使用,如何从lua_State中清除它而保留其他所有内容?如何最好地使用可能对函数/全局变量使用相同名称的脚本?如果我加载它们所有的话,新的定义将覆盖旧的定义。
在阅读在线文档后,我认为需要将每个加载的块 分隔开成不同的环境。我设想的方式是,每次加载块时,我都会为它指定一个唯一的环境名称,当我 需要使用它时,我只需使用该名称从
LUA_REGISTRYINDEX中获取该 环境并执行操作。到目前为止,我还没有想出如何去做。在线上有例子,但是它们使用的是 Lua 5.1。
点赞
用户1490747
经过一番探索,我找到了我想要的解决方案。我不确定这是否是正确/最好的方法,但它在我的基本测试中有效。@jpjacobs在这个问题的答案对我帮助很大。
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
我使用的是Lua 5.3.2和Visual Studio 2013,如果有任何意义的话。
这个基本测试案例满足了我的需求。我将继续测试,看看是否会出现任何问题/改进。如果有任何看起来可以改进这个代码或者有任何显眼的错误,请留言。
2016-04-04 17:12:33
用户9608077
你应该将你的每个脚本作为一个不同的模块对待。就像你的代码中有多于1个的 "require" 一样。
你的 'loaded chunk' 应该返回一个将被全局储存的表格。
加载许多全局变量并不是一个好主意,因为在你添加更多模块后,这可能会导致问题。
2016-04-04 22:33:50
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在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中获取用户配置主目录的跨平台方法
是的,除非这些脚本是不相关的,并且应在多个并行线程中运行。
代码块只是值为“function”的值。当您没有在任何地方存储该值时,代码块将被垃圾回收。
代码块生成的任何内容——全局变量或具有在外部引用的本地变量——都将继续存在。
这取决于您如何看待该代码块。它只是一组函数,还是代表具有自己状态的某个实体。如果没有创建全局函数和变量,那么在单独的脚本文件中定义的所有内容都将局部于代码块,并且在没有对代码块的引用时将被删除。
考虑重写您的代码。除非明确要求在程序的其他部分建立通信,否则不要创建任何全局变量。将变量设为本地(由块拥有),或将其存储在将由块返回为新对象的表/闭包中。代码块可能是生成新对象的工厂,而不仅仅是“脚本”。
此外,Lua 只需要更快的局部变量。
如果脚本来自外部——用户编写的或来自其他外部来源,请执行此操作。沙盒非常酷,但如果块是您的内部文件,则无需沙盒。考虑重新编写代码以避免全局变量。如果您的块生成其他对象,则返回一些对象(API 表或闭包)。您可以多次调用该块而无需重新加载它。或者,如果块表示类似 Lua 的模块,则保存一个全局变量——模块接口。如果您没有良好地组织代码,则将被迫使用单独的环境,并且您必须为每个脚本准备新环境,复制基本内容,如打印/对/字符串等。您将在运行时遇到许多中断,直到您弄清新环境中缺少什么为止,等等。