将全局环境设为只读(Lua)

我嵌入了Lua,并想让脚本能够读取全局表,但不能自动写入它,这样两个脚本就可以使用相同的变量名称而不互相覆盖,但仍然可以向全局表中添加内容。我无法更好地解释它:

脚本1

var1 = "foo"
_G.var2 = "bar"

脚本2

print(var1) -- 打印nil
print(var2) -- 打印'bar'

我尝试通过像这样做来实现它('scripts'是一个函数)

newScript = function(content)
    Script = loadstring(content)()
    env = setmetatable({},{__index = _G})
    setfenv(Script,env)
    return Script
end

我的Lua绑定是LuaJ,为了在此处提供所有信息,这里是该代码:

private LuaValue newScript(String content){
        LuaTable envMt = new LuaTable();
        envMt.set(INDEX, _G);
        LuaTable env = new LuaTable();
        env.setmetatable(envMt);

        LuaClosure func = (LuaClosure) _G.get("loadstring").call(valueOf(content));

        thread = new LuaThread(func,env);
        thread.resume(NIL);
        return thread;
}

原文链接 https://stackoverflow.com/questions/7145984

点赞
stackoverflow用户298661
stackoverflow用户298661

你想要改变的并不是__index,而是__newindex。另外,你不能使用__index来捕获访问表中已存在的键。使表在所有情况下只读的唯一方法是将所有读取延迟到代理表并在写入时抛出一个错误。

2011-08-22 10:33:01
stackoverflow用户596285
stackoverflow用户596285

以下是我用来返回只读表的函数:

function ro_table (t)
  local t = t
  if t then
    return setmetatable({},
      { __index=t,
        __newindex= function(_,_,_) error ("Attempt to modify read-only table") end,
      })
  else
    return nil
  end
end

那么对于你的代码,你可以这样做:

newScript = function(content)
    Script = loadstring(content)()
    setfenv(Script,ro_table(_G))
    return Script
end

请注意,这不会递归地起作用,因此如果您有任何定义为全局的表(或甚至是任何内置函数),则其内容可以被更改,但表本身不可被替换。

2011-08-22 11:52:42