7

可以说我至少有两个 lua 脚本文件。

测试1.lua 测试2.lua

两者都定义了一个 init 函数和其他具有相似名称的函数。

如何使用 c++/c 将每个脚本文件加载到使用 Lua 5.2 的单独环境中,以便相同的函数名称不会发生冲突 - 我发现 5.1 的示例代码对我不起作用(因为 setenv 消失了,而 lua_setuservalue 没有似乎工作)

Sample here使用句柄从 .lua 调用 lua 函数?

基本上,如果我用 setuservalue 替换 setenv - 我会遇到访问冲突。

4

2 回答 2

8

非官方的Lua FAQ有一个关于 Lua 沙盒的条目。我的猜测是,您可以轻松地将该逻辑转换为您的 C/C++ 代码。

另请参阅lua-users wiki 上的 LuaFiveTo

更正

这确实不像看起来那么微不足道。但最后一点很简单:加载你的块,推送 _ENV 表,使用lua_setupvalue(L,-2,1). 重要的是表格应该在堆栈的顶部。

作为一个小例子,使用 2 个默认为 _G 的环境通过元表读取内容:

#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()
于 2012-06-13T12:31:23.500 回答
0

两者都定义了一个 init 函数和其他具有相似名称的函数。

首先,为什么这些功能是全局的?它们应该是脚本的本地。如果您要require在其他文件中访问它们,它们应该创建并返回一个包含它们希望公开的函数的表。

需要这些文件时的现代习惯用法是执行以下操作:

local Library = require 'library'

Library.Func1(...)

因此,您不会污染全局 Lua 命名空间。您使用局部变量。

但是,如果您坚持使用这样的全局变量,您可以完全按照文档中的说明进行操作:更改已编译块的第一个上值。

基本上,如果我用 setuservalue 替换 setenv - 我会遇到访问冲突。

你当然知道。那lua_setuservalue 不是。它用于设置与userdata关联的值。你想要的被恰当地称为lua_setupvalue.

使用您引用的示例代码,正确答案是:

lua_setupvalue(L, -2, 1);
于 2012-06-13T14:31:58.380 回答