obsidian/笔记文件/2.笔记/Lua中的require与package.loaded.md
2025-03-26 00:02:56 +08:00

72 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#unity/日常积累
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
```lua
local testRequire = {name = "fightsyj"}
function testRequire:getName()
return self.name
end
function testRequire:setName(name)
self.name = name
end
return testRequire
```
test.lua
```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
]]
```