以下是在纯 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;
}