Lua C API - 加载具有相同名称的变量和函数的多个文件
Lua C API - loading multiple files with variables and functions of the same names
假设我有两个 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 代码的情况下,我怎样才能以调用特定 doSomething()
的方式加载文件?
有没有一种方法可以将 "everything" 从加载的文件(函数、变量、tables)移动到 lua_State
中的全局 table 使用脚本名称(或其他)作为关键?另外,有没有办法让 file1.lua 和 file2.lua 可以共享 common.lua 的 "in memory" 版本?
我正在使用 Lua 5.1.
谢谢!
以下是在纯 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
函数放在全局环境中,从而互相踩踏,它们会去在他们自己的本地环境中(使用元表,因此他们可以使用全局环境中的东西,如 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;
}
仅供参考,以上答案不再适用于最新版本的 LUA。具体来说,
lua_pushvalue(L, LUA_GLOBALSINDEX);
和
lua_setfenv(L, -2);
不再受支持。因为我是一个 LUA 新手,所以我不知道应该使用什么等效的 LUA api 调用作为替代。如果有人可以更新该答案以使用 LUA 5.4,将不胜感激。很抱歉,我没有遵守协议,没有直接在答案中发表评论,但我显然没有足够的声誉来这样做。
假设我有两个 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 代码的情况下,我怎样才能以调用特定 doSomething()
的方式加载文件?
有没有一种方法可以将 "everything" 从加载的文件(函数、变量、tables)移动到 lua_State
中的全局 table 使用脚本名称(或其他)作为关键?另外,有没有办法让 file1.lua 和 file2.lua 可以共享 common.lua 的 "in memory" 版本?
我正在使用 Lua 5.1.
谢谢!
以下是在纯 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
函数放在全局环境中,从而互相踩踏,它们会去在他们自己的本地环境中(使用元表,因此他们可以使用全局环境中的东西,如 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;
}
仅供参考,以上答案不再适用于最新版本的 LUA。具体来说,
lua_pushvalue(L, LUA_GLOBALSINDEX);
和
lua_setfenv(L, -2);
不再受支持。因为我是一个 LUA 新手,所以我不知道应该使用什么等效的 LUA api 调用作为替代。如果有人可以更新该答案以使用 LUA 5.4,将不胜感激。很抱歉,我没有遵守协议,没有直接在答案中发表评论,但我显然没有足够的声誉来这样做。