我了解到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
尽管这可以很好地工作,但我想知道是否可以更简化脚本A
的代码,或者是否存在其他替代解决方案将脚本公开给其他脚本。
添加:我问这的主要原因是因为我认为package.preload['A'] = function () return A end
相当长而且很无聊。
答案 0 :(得分:3)
在这种情况下,如果您有一些表示Lua模块的in-C字符串集,则package.preload
正是要使用的工具。尽管您对它的特定用法仍有待改进。
通常来说,模块本身并不定义其名称。因此,将模块名称硬编码到字符串中并不是正确的做法。同样,模块不会自行注册。它们应该由模块周围的环境注册。
您真正想要的是获取一个name + Lua代码字符串数组,并将其注册为循环中的模块预加载。所以你会有这样的事情。我将使用Lua 5.3;您可以轻松地将其翻译为旧版本的Lua。
还请注意:此代码未经测试。
const char *lua_preloads[] =
{
"A", "local A = {}\n"
"A.num = 3\n"
"return A)\n", //Modules are usually tables, not functions.
...
NULL //Null-terminated list.
};
//Loader function
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);
//Move the function to the bottom of the stack
lua_insert(lua_func_ix, 1);
//Call with all of the given arguments.
lua_call(L, nargs, LUA_MULTRET);
return lua_gettop(L);
}
int top = lua_gettop(L);
//Get the package.preload table.
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];
//Compile the preload script into a Lua function.
int err = luaL_loadbufferx(L, module, strlen(module), module_name, "t");
//Check for errors in `err`.
//Create a Lua C-function with the script as an upvalue.
lua_pushcclosure(L, lua_preloader_func, 1);
//Stick that Lua C-function inside of package.preload[preload.first].
lua_setfield(L, preload_ix, module_name);
}
lua_settop(L, top);
答案 1 :(得分:1)
似乎您想为每个定义模块的块加上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);
}