仅限全球环境访问(Lua)

时间:2011-08-22 10:18:22

标签: lua luaj

我嵌入了Lua并希望脚本能够读取全局表但不能自动写入它,因此两个脚本可以编写具有相同名称的变量而不会相互覆盖,但仍然可以将内容添加到全局表中。我无法真正解释它:

脚本1

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

脚本2

print(var1) -- Prints nil
print(var2) -- Prints 'bar'

我是如何通过做这样的事情来做到这一点的('脚本'是一个函数)

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;
}

2 个答案:

答案 0 :(得分:3)

您想要更改的不是__index,而是__newindex。此外,您无法使用__index来访问表中存在的密钥。在所有情况下使表成为只读的唯一方法是将所有读取推迟到代理表并在写入时抛出错误。

答案 1 :(得分:2)

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

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

请注意,这不会递归,因此如果您将任何表定义为全局(甚至任何内置函数),则可以更改内容,但无法替换表本身。