Lua C API - 加载多个具有相同名称的变量和函数的文件

假设我有两个使用标准Lua C API的Lua文件,共享一个公共库:

common.lua

function printHello(name)
    print("Hello from " .. name)
end

file1.lua

require "common"
local scriptName = "file1"

function doSomething()
    printHello(scriptName)
end

file2.lua

require "common"
local scriptName = "file2"

function doSomething()
    printHello(scriptName)
end

现在假设我想让file*.lua文件共享相同的 lua_State

在不改变任何Lua代码的情况下,如何以一种方式加载文件,以便我可以调用特定的 doSomething()呢?

是否有一种方法可以将从加载的文件(函数,变量,表)中的“一切”移动到 lua_State 中的全局表中,使用脚本名称(或其他内容)作为键?另外,是否有一种方法可以使file1.lua和file2.lua共享common.lua的“内存”版本?

我正在使用Lua 5.1。

谢谢!

点赞
用户7509065
用户7509065

以下是如何在纯 Lua 5.1 中实现:

file1_env = setmetatable({}, {__index = _G})
local file1_chunk = loadfile('file1.lua')
setfenv(file1_chunk, file1_env)
file1_chunk()

file2_env = setmetatable({}, {__index = _G})
local file2_chunk = loadfile('file2.lua')
setfenv(file2_chunk, file2_env)
file2_chunk()

file1_env.doSomething() -- 输出 "Hello from file1"
file2_env.doSomething() -- 输出 "Hello from file2"

实际上改变了每个文件块运行的环境,所以它们的“doSomething”函数不再在全局环境中,这样它们就可以使用自己的局部环境(其中使用了 metatable,因此它们可以使用全局环境中的东西,例如“require”和“print”)。如所请求的,'common.lua'只需运行一次,如果在其末尾放置像“printHello('common')”这样的语句,则会看到。

如果要从 C 中执行此操作,则可以将我使用的所有功能直接转换为 C API,如下所示:

#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#include <lua5.1/lauxlib.h>

int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    /* stack is empty */
    lua_createtable(L, 0, 1);
    /* -1: file1_env */
    lua_createtable(L, 0, 1);
    /* -2: file1_env, -1: file1_env_mt */
    lua_pushvalue(L, LUA_GLOBALSINDEX);
    /* -3: file1_env, -2: file1_env_mt, -1: _G */
    lua_setfield(L, -2, "__index");
    /* -2: file1_env, -1: file1_env_mt */
    lua_setmetatable(L, -2);
    /* -1: file1_env */
    luaL_loadfile(L, "file1.lua");
    /* -2: file1_env, -1: file1_chunk */
    lua_pushvalue(L, -2);
    /* -3: file1_env, -2: file1_chunk, -1: file1_env */
    lua_setfenv(L, -2);
    /* -2: file1_env, -1: file1_chunk */
    lua_call(L, 0, 0);
    /* -1: file1_env */
    lua_setglobal(L, "file1_env");
    /* stack is empty */
    lua_createtable(L, 0, 1);
    /* -1: file2_env */
    lua_createtable(L, 0, 1);
    /* -2: file2_env, -1: file2_env_mt */
    lua_pushvalue(L, LUA_GLOBALSINDEX);
    /* -3: file2_env, -2: file2_env_mt, -1: _G */
    lua_setfield(L, -2, "__index");
    /* -2: file2_env, -1: file2_env_mt */
    lua_setmetatable(L, -2);
    /* -1: file2_env */
    luaL_loadfile(L, "file2.lua");
    /* -2: file2_env, -1: file2_chunk */
    lua_pushvalue(L, -2);
    /* -3: file2_env, -2: file2_chunk, -1: file2_env */
    lua_setfenv(L, -2);
    /* -2: file2_env, -1: file2_chunk */
    lua_call(L, 0, 0);
    /* -1: file2_env */
    lua_setglobal(L, "file2_env");
    /* stack is empty */
    lua_getglobal(L, "file1_env");
    /* -1: file1_env */
    lua_getfield(L, -1, "doSomething");
    /* -2: file1_env, -1: file1_env.doSomething */
    lua_call(L, 0, 0);
    /* -1: file1_env */
    lua_pop(L, 1);
    /* stack is empty */
    lua_getglobal(L, "file2_env");
    /* -1: file2_env */
    lua_getfield(L, -1, "doSomething");
    /* -2: file2_env, -1: file2_env.doSomething */
    lua_call(L, 0, 0);
    /* -1: file2_env */
    lua_pop(L, 1);
    /* stack is empty */

    lua_close(L);
    return 0;
}
2020-05-08 17:10:54
用户4256006
用户4256006

FYI,上述答案现在已经不能在最新版本的LUA中使用。具体来说,



不再受支持。由于我是一个LUA新手,我不知道应该使用哪些等效的LUA api调用来替换它们。如果有人能更新那个答案,让它适用于LUA 5.4,那将不胜感激。我很抱歉我没有遵循协议,没有直接在答案中评论,但显然我没有足够的声誉来这样做。

2022-03-04 15:06:08