如何使 Lua/LuaJ 中的全局变量“不可变”?

描述

我正在做一个 LuaJ 程序,有一个如下所示的库脚本:

function foo()
    print("foo");
end

我希望 foo 函数能够在其他脚本中 直接 调用(不需要 require)并在不同脚本中表现为不可变的。即使脚本覆盖它,它也会在其他脚本中按原始方式执行。

例如,这是脚本 1:

foo = function()
    print("bar");
end

这是脚本 2:

foo();

已完成的工作

我看到了这两个问题。它们确实有效,但不是这个问题的解决方案。

LuaJ 如何避免覆盖全局表中的现有条目

防止 Lua 表中的函数覆盖

使全局环境仅能访问(Lua)


我尝试每次执行脚本时加载库,或设置 local _ENV,但由于可能会从 Java 回调到 Lua,它不能正常工作。

现在,我通过创建一个 Globals 并在 Java 中每次加载脚本时加载库脚本来处理它,如下所示:

    public static void main(String[] args) {
        loadAndCallViaDifferentEnv(libPath, script1);
        loadAndCallViaDifferentEnv(libPath, script2);
    }

    static void loadAndCallViaDifferentEnv(String libPath, String scriptPath) {
        Globals globals = JsePlatform.standardGlobals();
        globals.loadfile(libPath).call();
        globals.loadfile(scriptPath).call();
    }

它工作得很好,但代价很大。有没有更好的方法?

点赞
用户1847592
用户1847592

我假设你想要保护三个函数不被重写:foo1foo2print

-- 将foo1和foo2定义在保护表中而不是像平常一样定义全局变量
local protected = {}

function protected.foo1()
   print("foo1");
end

function protected.foo2()
   print("foo2");
end

-- 如果要保护的函数已经存在,则从全局变量中删除它:
protected.print = print
print = nil

-- 现在给全局变量设置元表
setmetatable(_G, {
   __index = protected,
   __newindex =
      function(t, k, v)
         if not protected[k] then
            rawset(t, k, v)
         end
      end
})

现在你可以从其他模块调用 foo1foo2print,而不需要 require,但是你不能覆盖它们:

-- 脚本1:
foo1 = function()
   print("bar");
end
foo1();   -- 调用原始的 protected.foo1()
-- 脚本2:
foo1();   -- 调用原始的 protected.foo1()
2021-06-01 03:27:12