假设我有至少两个lua脚本文件。
test1.lua test2.lua
都定义了一个init函数和其他具有相似名称的函数。
如何使用c ++ / c将每个脚本文件加载到使用Lua 5.2的单独环境中,以便相同的函数名称不会发生冲突 - 我发现5.1的示例代码对我不起作用(因为setenv已经消失了lua_setuservalue似乎不起作用)
此处示例Calling lua functions from .lua's using handles?
基本上如果我用setuservalue替换setenv - 我会收到访问冲突。
答案 0 :(得分:8)
unofficial Lua FAQ在Lua中有一个关于沙盒的条目。 我的猜测是你可以很容易地将这个逻辑转换成你的C / C ++代码。
另见LuaFiveTo on the lua-users wiki。
<强>校正强>
这确实不像看起来那么微不足道。但最后要点很简单:加载块,按_ENV表,使用lua_setupvalue(L,-2,1)
。重要的是表格应该位于堆栈的顶部。
作为一个小例子,使用2个环境默认为_G通过metatables读取内容:
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int main(void){
lua_State *L = luaL_newstate();
char *file1 = "file1.lua";
char *file2 = "file2.lua";
luaL_openlibs(L);
luaL_loadfile(L,file2); // S: 1
luaL_loadfile(L,file1); // S: 2
lua_newtable(L); // ENV for file 1: S: 321
lua_newtable(L); // ENV for file 2: S: 4321
//lets have each function have its metatable, where missed lookups are
//instead looked up in the global table _G
lua_newtable(L); // metatable S: 54321
lua_getglobal(L,"_G"); // pushes _G, which will be the __index metatable entry S: 654321
lua_setfield(L,-2,"__index"); // metatable on top S: 54321
lua_pushvalue(L,-1); // copy the metatable S: 554321
lua_setmetatable(L,-3); // set the last copy for env2 S: 54321
lua_setmetatable(L,-3); // set the original for env1 S: 4321
// here we end up having 2 tables on the stack for 2 environments
lua_setupvalue(L,1,1); // first upvalue == _ENV so set it. S: 321
lua_setupvalue(L,2,1); // set _ENV for file S: 21
// Remaining on the stack: 2 chunks with env set.
lua_pcall(L,0,LUA_MULTRET,0);
lua_pcall(L,0,LUA_MULTRET,0);
lua_close(L);
return 0;
}
对于2个Lua文件:
-- file1.lua
function init()
A="foo"
print("Hello from file1")
print(A)
end
init()
-- file2.lua
-- this shows that stuff defined in file1 will not polute the environment for file2
print("init function is",tostring(init))
function init()
A="bar"
print("Hello from file2")
print(A)
end
init()
答案 1 :(得分:0)
都定义了一个init函数和其他具有相似名称的函数。
首先,为什么这些功能全球?它们应该是脚本的本地。如果你要在其他文件中require
,他们应该创建并返回一个包含他们希望公开的函数的表。
当需要这些文件时,现代习语就是做这样的事情:
local Library = require 'library'
Library.Func1(...)
因此,您不会污染全局Lua名称空间。您使用局部变量。
但是,如果你坚持使用像这样的全局变量,你可以完全按照文档所说的做法:改变已编译块的第一个upvalue。
基本上如果我用setuservalue替换setenv - 我会收到访问冲突。
你当然可以。这不是lua_setuservalue
所做的。它用于设置与 userdata 关联的值。你想要的是恰当地称为lua_setupvalue
。
使用您引用的示例代码,正确的答案是:
lua_setupvalue(L, -2, 1);