Lua C API - загрузка нескольких файлов с одинаковыми именами переменных и функций - PullRequest
2 голосов
/ 08 мая 2020

Допустим, у меня есть два Lua файла, которые я буду использовать из стандартного Lua C API, которые имеют общую библиотеку:

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

Теперь скажем, что я хочу, чтобы оба файла *. lua совместно использовали то же lua_State. Без изменения какого-либо кода Lua , как мне загрузить файлы таким образом, чтобы я мог вызвать специфику c doSomething()?

Есть ли способ, которым я могу переместить "все" из загруженных файлов (функций, переменных, таблиц) в глобальную таблицу внутри lua_State, используя имя сценария (или что-то еще) в качестве ключа? Кроме того, есть ли способ сделать это так, чтобы file1. lua и file2. lua могли совместно использовать версию common. lua?

Я использую Lua 5.1.

Спасибо!

1 Ответ

1 голос
/ 08 мая 2020

Вот как вы это делаете в чистом 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() -- prints "Hello from file1"
file2_env.doSomething() -- prints "Hello from file2"

Что происходит, вы меняете среду, в которой работает каждый фрагмент файла, поэтому вместо того, чтобы помещать их doSomething функции в глобальной среде и, таким образом, наступая друг на друга, они go в своей собственной локальной среде (которая использует метатаблицу, чтобы они могли использовать вещи, которые находятся в глобальной среде, например 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...