Lua中的require與package.loaded

require (modname)

加載一個模塊。 這個函數首先查找 package.loaded 表, 檢測 modname 是否被加載過。 如果被加載過,require 返回 package.loaded[modname] 中保存的值。 否則,它試着爲模塊尋找 加載器 。
require 遵循 package.searchers 序列的指引來查找加載器。 如果改變這個序列,我們可以改變 require 如何查找一個模塊。 下列說明基於 package.searchers 的默認配置。
首先 require 查找 package.preload[modname] 。 如果這裏有一個值,這個值(必須是一個函數)就是那個加載器。 否則 require 使用 Lua 加載器去查找 package.path 的路徑。 如果查找失敗,接着使用 C 加載器去查找 package.cpath 的路徑。 如果都失敗了,再嘗試 一體化 加載器 (參見 package.searchers)。
每次找到一個加載器,require 都用兩個參數調用加載器: modname 和一個在獲取加載器過程中得到的參數。 (如果通過查找文件得到的加載器,這個額外參數是文件名。) 如果加載器返回非空值, require 將這個值賦給 package.loaded[modname]。 如果加載器沒能返回一個非空值用於賦給 package.loaded[modname], require 會在那裏設入 true 。 無論是什麼情況,require 都會返回 package.loaded[modname] 的最終值。
如果在加載或運行模塊時有錯誤, 或是無法爲模塊找到加載器, require 都會拋出錯誤。

package.loaded

用於 require 控制哪些模塊已經被加載的表。 當你請求一個 modname 模塊,且 package.loaded[modname] 不爲假時, require 簡單返回儲存在內的值。
這個變量僅僅是對真正那張表的引用; 改變這個值並不會改變 require 使用的表。

簡而言之就是:
在Lua中使用require進行模塊的加載,被成功加載的模塊會將這個模塊的引用保存到package.loaded表中;在使用require進行模塊加載的時候,會首先在package.loaded表中查找,檢測這個模塊是否被加載過,如果被加載過則返回這個模塊在package.loaded中保存的值,否則加載這個模塊!

那麼問題來了,如果現在我需要重新加載一個已被成功加載過的模塊呢?

例如:在進行更新之前就已經require過某一個模塊,恰好本次的更新內容中就包含了這個模塊的更新,在更新完成之後這個模塊的內容發生了改變,但是由於在更新之前就已經require過了,package.loaded表中保存的這個模塊的引用還是舊的,重新require無效!

其實解決辦法很簡單:在重新require之前將這個模塊在package.loaded中保存的引用置空即可!

Test Demo
testRequire.lua

local testRequire = {name = "fightsyj"}

function testRequire:getName()
	return self.name
end

function testRequire:setName(name)
	self.name = name
end

return testRequire

test.lua

local modname = "testRequire"
local testRequire = require(modname)
print("------------------------------")
print(testRequire:getName())

delayDoSomething(function()
	testRequire = require(modname)  -- 在文件動態改變之後,重新require返回的依舊是原來就文件內容的引用
	print("------------------------------")
	print(testRequire:getName())

	package.loaded[modname] = nil  --package.loaded表中保存的目標引用置空
	testRequire = require(modname)  -- 重新require這個模塊
	print("------------------------------")
	print(testRequire:getName())
end, 5)  -- 延時5s,在這5s之內將testRequire.lua中的{name = "fightsyj"}改爲{name = "fightsyj2"}

--[[ 
------------------------------
fightsyj
------------------------------
fightsyj
------------------------------
fightsyj2
]]

ps
delayDoSomething

參考:
Lua 5.3 參考手冊

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