Lua中有替代package.preload的方案吗?

我发现package.preload可以用于将脚本暴露给其他脚本使用。

这是我的示例代码:

lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
//Script A
luaL_dostring(L, "local A = {} package.preload['A'] = function () return A end A.num = 3");
//Script B
luaL_dostring(L, "local A = require 'A' print(A.num)");
lua_close(L);

结果是:3

虽然这个方法可以使用,但是我想知道Script A的代码是否可以更简洁,或是否有其他替代方法来将脚本暴露给其他脚本使用。

补充:我提出这个问题的主要原因是,我认为package.preload['A'] = function () return A end太长而且无聊了。

点赞
用户734069
用户734069

在这种情况下,当您拥有一些代表 Lua 模块的 in-C 字符串集时,“package.preload”正是要使用的工具。尽管您特定的使用留下了一些问题。

一般来说,模块本身并不定义它们的名称。因此,将模块的名称硬编码到字符串中不是正确的方法。类似地,模块不会注册自己;它们应该由围绕模块的环境注册。

你真正想要的是将名称+Lua 代码字符串数组作为模块预加载在循环中注册。因此,您会得到类似这样的结果。我将使用 Lua 5.3;您可以轻松地将其翻译为旧版的 Lua。

还要注意:此代码未经测试。

const char *lua_preloads[] =
{
    "A", "local A = {}\n"
        "A.num = 3\n"
        "return A)\n", //模块通常是表而不是函数。
    ...
    NULL // Null-terminated list.
};

//加载器函数
int lua_preloader_func(lua_State *L)
{
    int nargs = lua_gettop(L);
    int lua_func_ix = lua_upvalueindex(1);
    lua_pushvalue(L, lua_func_ix);

    //将函数移动到堆栈的底部
    lua_insert(lua_func_ix, 1);

    //用所有给定的参数调用。
    lua_call(L, nargs, LUA_MULTRET);
    return lua_gettop(L);
}

int top = lua_gettop(L);

//获取 package.preload 表。
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
int preload_ix = lua_gettop();

for(const char **position = lua_preloads;
    *position;
    position += 2)
{
    const char *module_name = position[0];
    const char *module = position[1];

    //将预装脚本编译成 Lua 函数。
    int err = luaL_loadbufferx(L, module, strlen(module), module_name, "t");

    //检查 `err` 中的错误。

    //使用脚本作为 upvalue 创建 Lua C 函数。
    lua_pushcclosure(L, lua_preloader_func, 1);

    //将该 Lua C 函数放在 package.preload[preload.first] 中。
    lua_setfield(L, preload_ix, module_name);
}

lua_settop(L, top);
2018-07-17 16:47:46
用户1944004
用户1944004

似乎您想在定义模块块的每个代码片段中添加 local A = {} package.preload['A'] = function () return A end (其中 A 是模块名称)。 我认为,只需使用字符串连接就可以简单地完成。

#include <string>
#include <lua.hpp>

int preload(lua_State *L, std::string const &modname,
            std::string const &modcode) {
    std::string code = "package.preload['" + modname + "'] = function()\n" +
                       "local " + modname + " = {}\n" + modcode + "\n"
                       "return " + modname + " end";
    return luaL_dostring(L, code.c_str());
}

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

    // Script A
    preload(L, "A", "A.num = 3");
    // Script B
    luaL_dostring(L, "local A = require 'A' print(A.num)");
    lua_close(L);
}
2018-07-18 05:13:18