簡體   English   中英

單個Lua狀態中的多個腳本並使用_ENV

[英]Multiple scripts in a single Lua state and working with _ENV

我目前正在學習如何使用Lua C API,雖然我在C / C ++和Lua之間有成功的綁定功能,但我有幾個問題:

  1. 將多個腳本加載到單個lua_State是一個好主意嗎? 有沒有辦法關閉特定的塊? 如果腳本不再使用,如何在保留其他所有內容的情況下從lua_State清除它?

  2. 使用可能對函數/全局變量使用相同名稱的腳本的最佳方法是什么? 如果我加載所有這些,則較新的定義會覆蓋舊的定義。

    在線閱讀后,我想我需要將每個加載的塊分成不同的環境。 我設想這個工作的方式是每次加載一個塊我為它分配一個唯一的環境名稱,當我需要使用它時,我只使用該名稱從LUA_REGISTRYINDEX獲取環境並執行操作。 到目前為止,我還沒有想出如何做到這一點。 網上有例子,但他們使用的是Lua 5.1。

在探索了一些后,我發現我認為是我正在尋找的解決方案。 我不確定這是否是正確/最好的方法,但它適用於我的基本測試用例。 @jpjacobs對這個問題的回答幫了很多忙。

test1.lua

x = 1
function hi()
    print("hi1");
    print(x);
end
hi()

test2.lua

x =2
function hi()
    print("hi2");
    print(x);
end
hi()

main.cpp中

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

    char* file1 = "Rooms/test1.lua";
    char* file2 = "Rooms/test2.lua";

    //We load the file
    luaL_loadfile(L, file1);
    //Create _ENV tables
    lua_newtable(L);
    //Create metatable
    lua_newtable(L);
    //Get the global table
    lua_getglobal(L, "_G");
    lua_setfield(L, -2, "__index");
    //Set global as the metatable
    lua_setmetatable(L, -2);
    //Push to registry with a unique name.
    //I feel like these 2 steps could be merged or replaced but I'm not sure how
    lua_setfield(L, LUA_REGISTRYINDEX, "test1");
    //Retrieve it. 
    lua_getfield(L, LUA_REGISTRYINDEX, "test1");
    //Set the upvalue (_ENV)
    lua_setupvalue(L, 1, 1);
    //Run chunks
    lua_pcall(L, 0, LUA_MULTRET, 0);

    //Repeat
    luaL_loadfile(L, file2);
    lua_newtable(L);
    lua_newtable(L);
    lua_getglobal(L, "_G");
    lua_setfield(L, -2, "__index");
    lua_setmetatable(L, -2);
    lua_setfield(L, LUA_REGISTRYINDEX, "test2");
    lua_getfield(L, LUA_REGISTRYINDEX, "test2");
    lua_setupvalue(L, 1, 1);
    lua_pcall(L, 0, LUA_MULTRET, 0);

    //Retrieve the table containing the functions of the chunk
    lua_getfield(L, LUA_REGISTRYINDEX, "test1");
    //Get the function we want to call
    lua_getfield(L, -1, "hi");
    //Call it
    lua_call(L, 0, 0);
    //Repeat
    lua_getfield(L, LUA_REGISTRYINDEX, "test2");
    lua_getfield(L, -1, "hi");
    lua_call(L, 0, 0);
    lua_getfield(L, LUA_REGISTRYINDEX, "test2");
    lua_getfield(L, -1, "hi");
    lua_call(L, 0, 0);
    lua_getfield(L, LUA_REGISTRYINDEX, "test1");
    lua_getfield(L, -1, "hi");
    lua_call(L, 0, 0);

    lua_close(L);
}

輸出:

hi1
1
hi2
2
hi1
1
hi2
2
hi2
2
hi1
1

如果這意味着什么,我在Visual Studio 2013中使用Lua 5.3.2。

此基本測試用例可根據需要運行。 我會繼續測試,看看是否有任何問題/改進。 如果有任何方式我可以改進此代碼或明顯錯誤,請發表評論。

將多個腳本加載到單個lua_State中是一個好主意嗎?

當然是。 除非這些腳本不相關並且應該在多個並行線程中運行。

有沒有辦法關閉特定的塊?

塊只是“函數”類型的值。 當你沒有將值存儲在任何地方時 - chunk將被垃圾收集。
任何產生的塊 - 全局變量,或者在外面有引用的本地人 - 都將繼續存在。

如何在保留其他所有內容的同時從lua_State中清除它?

這取決於你如何看待那塊。 它只是一組函數,還是代表某個具有自己狀態的實體。 如果您不創建全局函數和變量,那么在單獨的腳本文件中定義的所有內容都將是塊的本地,並且在沒有對塊的引用時將被刪除。

使用可能對函數/全局變量使用相同名稱的腳本的最佳方法是什么?

考慮重寫代碼。 不要創建任何全局變量,除非明確要求與程序的其他部分建立通信。 使變量本地(由chunk擁有),或將其存儲在將由chunk作為新對象返回的表/閉包中 - chunk可能是生成新對象的工廠,而不是jush 腳本
Lua也使用局部變量運行得更快。

我設想這個工作的方式是每次加載一個塊我給它分配一個唯一的環境名稱

如果腳本來自外部 - 由用戶編寫或從其他外部源接收,則應該這樣做。 沙盒很酷,但是如果塊是你的內部東西,則不需要沙盒。 考慮重寫沒有全局變量的代碼。 如果你的塊產生其他對象,則返回一些對象(api表或閉包) - 你可以多次調用該塊而無需重新加載它。 或者保存一個全局模塊接口,如果chunk代表Lua-like模塊。 如果你沒有很好地組織你的代碼,那么你將被迫使用單獨的環境,你必須為每個腳本准備新的環境,復制print / pairs / string /等基本內容。 在運行時間你會有很多休息時間,直到你弄清楚新環境中缺少什么,等等。

您應該將每個腳本視為不同的模塊。 就像你的代碼中有超過1“需要”一樣。

你的'加載的塊'應該返回將全局存儲的表。

加載很多全局變量並不是一個好主意,這會在你添加更多模塊后造成壞處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM