【问题标题】:How to share global variables between Lua scripts如何在 Lua 脚本之间共享全局变量
【发布时间】:2018-07-14 10:52:47
【问题描述】:

我想知道如何在 Lua 脚本之间共享全局变量。

我尝试使用require 自己执行此操作,但它没有按我的预期工作。

这是我的简单示例代码。

test.lua

num = 2

A.lua

require(`test`);
num = 5

B.lua

require(`test`);
print(num);

如果我先运行A.lua,然后运行B.lua,我会得到以下结果:

2

但我希望得到5,因为我在A.lua 中将变量值修改为2

有没有可能实现我想要的? (我会很感激一个例子)

【问题讨论】:

    标签: lua


    【解决方案1】:

    您目前正在做的事情如下:

    lua A.lua
    > lua process starts
    > loading A.lua
    > loading test.lua (because it is required by A.lua)
    > set global "num" to value 2
    > set global "num" to value 5
    > lua process exits (A.lua finished)
    lua B.lua
    > lua process starts
    > loading B.lua
    > loading test.lua (because it is required by B.lua)
    > set global "num" to value 2
    > print global "num" (which was set to 2 by test.lua)
    > lua process exits (B.lua finished)
    

    要打印值 5,您的脚本应如下所示:

    -- test.lua
    num = 2
    
    -- A.lua
    require("test")
    num = 5
    
    -- B.lua
    require("test")
    require("A")
    print(num)
    

    这将导致:

    lua B.lua
    > lua process starts
    > loading B.lua
    > loading test.lua (because it is required by B.lua)
    > set global "num" to value 2
    > loading A.lua (because it is required by B.lua)
    > skip loading test.lua (has already been loaded)
    > set global "num" to value 5
    > print global "num"
    > lua process exits (B.lua finished)
    

    编辑: 我看到您正在使用 Lua 的 C Api 而不是 Lua 二进制文件来执行您的脚本。使用编程 api,您应该能够通过使用相同的 lua 状态(通常存储在 C 变量“L”中)执行 A.lua 和 B.lua 来获得所需的结果。

    【讨论】:

    • 您好,非常感谢您的详细解释。现在我明白它是如何工作的了。你能给我看一个Using the programming api you should be able the get your required result by executing A.lua and B.lua using the same lua-state的例子吗?
    • 我自己从未使用过编程 api,但是只要你通过相同的 lua_State *L = luaL_newstate(); 两个脚本执行,你应该没问题。
    【解决方案2】:

    a.lua

    a = 5
    

    b.lua

    require('a')
    a = 2
    

    test.lua

    require('b')
    print(a)
    

    你应该得到 2,因为 require 链是从上到下工作的,如果你只是运行每个文件一次 lua 将执行这个小 uniq 执行,在不同的执行中没有持久性,所以你需要根据需要 require

    【讨论】:

      【解决方案3】:

      没有专门的函数需要来自 C-API 的 Lua 模块。[1] 所以我将自己定位于 Lua 解释器中的函数 dolibrary 来实现 require,它只是调用来自 C 的 Lua require 函数。

      注:我不建议让模块通过共享全局变量进行通信,尤其是当加载模块的顺序很重要时,就像这里的情况一样。最好提供 A.update_num(old)B.update_num(old) 方法,它们将 num 的旧值作为参数并返回更新后的值。

      #include <iostream>
      
      #include <lua.hpp>
      
      int require(lua_State *L, char const * modname) {
          int const size = lua_gettop(L);
      
          lua_getglobal(L, "require");
          lua_pushstring(L, modname);
      
          if (lua_pcall(L, 1, LUA_MULTRET, 0) != 0) {
              std::cerr << "lua:" << lua_tostring(L, 1) << '\n';
              lua_pop(L,1);
              return 0; // Failed, nothing should be on the stack
          }
      
          return lua_gettop(L) - size;
      }
      
      int main() {
          lua_State *L = luaL_newstate();
          luaL_openlibs(L);
      
          require(L, "A");
          require(L, "B");
      
          lua_close(L);
      }
      

      将您问题中的脚本放在我们得到的同一目录中:

      $ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2/ test.cpp -llua5.2
      $ ./a.out 
      5
      

      [1] lua_requiref 需要来自 C-API 的 Lua C 模块。

      【讨论】:

      • 谢谢先生。尽管知道它非常有用,但我认为它并不能真正回答我想要解决的问题。如果您能看看我发布的另一个问题,我将不胜感激:*.com/questions/51335428/…