Lua熱更原理以及加載規則

要實現Lua的熱更新,首先要了解Lua的模塊加載機制,熱更新的核心就是替換package.loaded的模塊。

加載規則:

包管理庫提供了從Lua中加載模塊的基礎庫。只有一個導出函數直接放在全局環境中:require。所有其他的部分都導出在表package中。

require(modname)

查詢全局緩存表package.loaded這個函數首先查找package.loaded表,檢測modname是否被加載過。如果被加載過,require返回package.loaded[modname]中保存的值。否則,它試着爲模塊尋找加載器。

通過package.searchers查找加載器:require遵循package.searchers序列的指引來查找加載器。如果改變package.searchers中的序列,也會改變require如何查找一個模塊的方式。

查找加載器:首先require查找package.preload[modname]。如果這裏有一個值(必須是一個函數),則爲加載器。否則require會使用Lua加載器去查找package.path的路徑。如果查找失敗,接着使用C加載器去查找package.cpath的路徑。如果都失敗了,再嘗試一體化加載器(參見package.searchers詳解)

加載器調用規則:每當找到一個加載器,require都用兩個參數調用加載器:modname和一個在獲取加載器過程中得到的參數(如果是通過查找文件得到的加載器,這個額外的參數即爲文件名)。如果加載器返歸非空值,require將這個值賦給package.loaded[modname]。如果加載器沒能返回一個非空值用於賦給package.loaded[modname]require 會將true賦給 package.loaded[modname]。 無論加載器返回什麼結果,require都會爲package.loaded[modname]設置最終值。

報錯:在加載或運行模塊時有錯誤,或是無法爲模塊找到加載器,require都會拋出錯誤。

package.loaded

存儲已經被加載的模塊:require一個modname模塊得到的結果不爲假時,require返回這個存儲的值。requirepackage.loader中獲得的值僅僅是對那張表(模塊)的引用,改變這個值並不會改變require使用的表(模塊)。

package.preload

保存一些特殊模塊的加載器:這裏面的值僅僅是對那張表(模塊)的引用,改變這個值並不會改變require使用的表(模塊)。

package.path

Lua加載器的搜索路徑:使用環境變量LUA_PATH_5_3LUA_PATH初始化。或者採用luaconf.h中的默認路徑。環境變量中的所有";;"都會被替換爲默認路徑。

package.cpath

C加載器的搜索路徑:使用環境變量LUA_CPATH_5_3LUA_CPATH初始化。或者採用luaconf.h中定義的默認路徑。

package.searchers

require查找加載器的表:這個表內的每一項都是一個查找器函數。當加載一個模塊時,require按次序調用這些查找器,傳入modname作爲唯一參數。此方法會返回一個函數(模塊的加載器)和一個傳給這個加載器的參數。或返回一個描述爲什麼沒有找到這個模塊的字符串或者nil

Lua共有四個查找器函數:

第一個查找器就是簡單的在package.preload表中查找;

第二個查找器用於查找Lua庫的加載庫。它使用存儲在package.path中的路徑查找工作。查找過程和函數package.searchpath描述的一致;

第三個查找器用於查找C庫的加載庫。它使用存儲在package.coath中的路徑查找工作。查找過程和函數package.searchpath描述的一致;

第四個搜索器是一體化加載器,從C路徑中查找指定模塊的根名字。

除了第一個搜索器外,每個搜索器都會返回找到的模塊的文件名。這和package.searchpath的返回值一樣,第一個搜索器沒有返回值。

package.searchpath(name, path[,sep[,,rep]])

在指定的path中搜索指定的name:路徑是一個包含一些列分號分隔的模板構成的字符串。對於每個模板,都會用name替換其中的每個問號(前提是有問號)。且將其中的sep(點".")替換爲rep(系統的目錄分隔符"/")。談候場時打開這個文件名。

例如,如果路徑是字符串  "./?.lua;./?.lc;/usr/local/?/init.lua"  

搜索foo.a 這個名字將一次嘗試打開文件./foo/a.lua      ./foo/a.lc   以及 /usr/local/foo/a/init.lua

返回第一個可以用讀模式打開(並馬上關閉該文件)的文件的名字。如果不存在這樣的文件,返回nil加上錯誤的消息。(錯誤消息列出了所有嘗試打開的文件名)
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章