2016-02-16 15 views
5

我有一個運行Lua腳本的應用程序。每個Lua腳本可能會運行多次。每次按下某個鍵時,甚至可能會運行一些腳本。Lua - 在不重新解析腳本的情況下重置狀態

我希望這些腳本在每次運行之間「重置」。即,如果用戶設置了變量Foo,則在下次運行時,Foo不應該存在於腳本中,直到用戶再次定義爲止。

問題是,如果我想要有這樣的行爲,我需要每次創建一個新的lua_State,然後每次打開它,然後每次解析腳本文件,這似乎很沒有優化。

加載庫可能是一個相當輕量級的操作(我假設),但解析腳本可能不是。

有沒有辦法重置Lua腳本的狀態(即清除用戶代碼定義的變量)而不創建新的lua_State並重新解析整個Lua腳本文件?我只希望腳本文件在應用程序啓動時被解析一次,因爲它們在運行時不會被修改。

謝謝。 :)

編輯:我發現這個話題,但它沒有詳細說明要做到這一點:http://lua-users.org/lists/lua-l/2006-01/msg00493.html

編輯:lua_setfenv似乎與這一點。我會多挖一點。

編輯:好像沒有更多的LUA 5.2的lua_setfenv。由於我使用5.3,我必須設置environement(即隱藏表nammed _ENV,其中存放變量)以便做到這一點,並因此重新加載所有內容,這是我不想做的事情...

+0

你可以做到這一點與協程可能嗎? – warspyking

回答

1

上次我看着這個答案是否定的,不幸的是。

您還需要記住的Lua可以調用庫,可以打開文件,malloc()內存等,而任何「重置」需要處理關閉這些文件,釋放內存等

作爲「重置」Lua狀態的替代方法,您可以簡單地組織代碼,以便它不需要重置;這顯然需要以特定的方式寫入Lua代碼。一種方法是堅持你的Lua代碼完全(或幾乎全部)包含在函數中,併爲每個動作調用一個或多個函數。函數外的代碼可能(例如)返回一個由引用組成的Lua表,以調用特定的入口點;這隻會被調用一次。函數被調用後會自行清除,包括清理任何庫分配的項目,打開文件等。應避免使用全局變量(除非常量)。我們成功地使用這種方法來確保Lua只被解析一次,入口點只確定一次,但相對較小的函數可以非常迅速地調用,而且開銷很小。

在您建議的註釋中,您可以將Lua代碼以詞法形式包裝在功能塊中。我認爲這是比上面的方法靈活,並具有以下缺點:

  • 你失去機會做一個「一次性初始化」(如例如從磁盤讀取一個固定常數)

  • 你,如果用戶插入(例如)不匹配end ... function B()在他們的代碼

  • 您約束自己每Lua的狀態一個入口點風險有不測風雲。

這意味着必須以不同的方式寫入Lua代碼(本質上Lua編碼器以所需的形式提供代碼)。解決這個問題的一個可能的方法是使用固定框架來執行此操作,並在代碼中調用require作爲庫。我還沒有嘗試過這種方法。

+0

感謝您的幫助。如果某些庫正在分配資源,那麼在刪除所有用戶變量時是否不應該自動釋放/垃圾收集這些資源? 也可以在運行腳本之前手動刪除_ENV中的所有值並執行類似lua_settop(0)的操作來重置堆棧? – Virus721

+0

另一個問題可能以另一種方式解決我的問題:如果所有用戶創建的變量都是使用本地定義的,然後將腳本封裝到函數中,然後再解析它?當函數結束時,它所有的本地代碼都會被銷燬嗎? – Virus721

+0

@ Virus721 - 當然,如果程序有效地重置自己(或者不需要重新設置),那就行了。我們所做的與此非常相似,因爲在全球範圍內,它只是返回一個指向函數的指針(IIRC--自從我查看它以來已經很長時間了),並且該函數本身應該以一種在清除後本身。但我不確定有什麼方法可以從程序外部重置任意* Lua程序。我不認爲'刪除所有用戶變量'的方法會飛,因爲您可能需要知道刪除它們的順序。 – abligh

0

難道你不能清除lua_State嗎?刪除所有線程和手動設置的全局變量。您可能需要將用戶環境與全局環境分開。

+0

「用戶環境」是否與lua_State隔離? – Virus721

+0

有一個全球環境,其中包含「表」和「打印」等東西。根據實施情況,這也是用戶環境。如果用戶做''a = 123''',那麼在全球環境中有一個字段_a_。你可以用一個簡單的getfenv/setfenv(或_ENV)將它分離出C端(我不知道如何)或者Lua端,用metafield __index創建一個指向舊的環境的新環境。 – EinsteinK

相關問題