Lua的module和require

一.Lua中的模块(module)

模块官方的定义

Programming in Lua(第四版)中对于模块的定义:

From the point of view of the user, a module is some code (either in Lua or in C) that can be loaded throughthe function require and that creates and returns a table. Everything that the module exports, such asfunctions and constants, it defines inside this table, which works as a kind of namespace.

从用户的角度来看,模块是一段代码(可以用 Lua 或 C 编写),可以通过 `require` 函数加载, 并创建一个表返回**。**模块导出的所有内容,例如函数和常量,都定义在这个表中,该表起到命名空间的作用。

精简结论:模块是可以通过require函数加载的Lua或C文件,eg:

包(package)是模块的集合

二.require函数

require函数的作用是加载一个模块,有一个参数:模块名称。require的括号是可选的:

Lua 复制代码
require('M') 等价于 require 'M'

2.1 require工作原理

require执行时,eg:

Lua 复制代码
require("module1")

第一步是检查package.loaded.module1是否存在,

若不存在,如下图所示

则加载module1(module1.lua的代码从上到下执行),

require执行完成后,会将返回值赋值给package.loaded.module1。

若已存在,直接返回package.loaded.module1;

特殊情况:模块没有返回值时,require返回true,并将package.loaded.module1赋值为true,从而后续再次require该模块的时候,和有返回值一致,不会再次加载该模块

Lua 复制代码
local M = {}
local index = 0
function M.Func()
	index = index + 1
	print("calling M.Func", index)
end

-- return M

要 require 加载同一个模块两次,可以从 package.loaded 中删除该库条目,这点非常有用,比如你修改了Lua文件,想在不重启游戏的情况下让其生效,只需要执行package.loaded.module1 = nil后,再次require就可以了

Lua 复制代码
package.loaded.module1 = nil
require("module1")

2.2 require搜索路径

package.path保存require使用的搜索路径,每个路径是一个包含可选问号的模板,模板中的问号会被替换成模块名。模板用分号分割,从第一个模板开始,若没找到模块则访问第二个模板。eg:

Lua 复制代码
package.path = ".\?.lua;.\?\init.lua"

下面展示若干example:在Assets/TestRequire/A.lua中调用require,访问B.lua

A.lua

Lua 复制代码
local B = require("B")

local M = {lv = 15, name = "A"}

return M

B.lua

Lua 复制代码
local M = {lv = 22, name = "B"}

return M

1.使用绝对路径

package.path包含module的绝对路径,?替换module名

路径分隔符推荐用正斜杠/,也可用双反斜杠\\,但反斜杠\被视作转义字符,不可用

Lua 复制代码
package.path = "D:/U3DP/?.lua;"		 --正确:正斜杠
--package.path = "D:\\U3DP\\?.lua;"	 --正确:双反斜杠
-- package.path = "D:\U3DP\?.lua;"	 --错误:单反斜杠视作转义字符
local B = require("B")
local M = {lv = 15, name = "A"}
return M

2. package.path匹配全部失败时会报错

3.按目录匹配

package.path保存的模板中,?不仅可用作文件名占位,也可用作目录占位:

Lua 复制代码
package.path = "D:/U3DP/?/init.lua;"
local B = require("B")
local M = {lv = 15, name = "A"}
return M

4.使用相对目录

package.path = "?.lua" 代表在当前工作目录替换问号,当前工作目录可通过下面的get_current_dir函数获取,将B放到该工作目录后,成功被 A require到

Lua 复制代码
local function get_current_dir()
    local handle
    if package.config:sub(1,1) == '\\' then
        -- Windows
        handle = io.popen("cd")
    else
        -- Linux/Mac
        handle = io.popen("pwd")
    end
    local result = handle:read("*a")
    handle:close()
    return result:gsub("\n", "")
end

print("当前工作目录: " .. get_current_dir())

package.path = "?.lua"
local B = require("B")
local M = {lv = 15, name = "A"}
return M

5.使用子模块

require的参数可以包含路径名,在不改动package.path的情况下,require到指定文件。比如A.B,在搜索时会被转化成A/B,点号会被转化成/。

Lua 复制代码
package.path = "?.lua"
local B = require("A.B")
local M = {lv = 15, name = "A"}
return M

三.子模块和包

Lua 允许模块名称具有层级结构,使用点号分隔不同的名称级别。例如,名为 mod.sub 的模块是 mod 的子模块。包是模块的完整树状结构,也是 Lua 中的分发单元。require子模块时按以下方式执行:eg:require("mod.sub")

├─ 1. package.loaded"mod.sub" 有吗? → 有则直接返回

├─ 2. package.preload"mod.sub" 有吗? → 有则直接返回

└─ 3. 把 "mod.sub" 转成 "mod/sub"(或 mod\sub)

按 package.path 查找文件

例如:mod/sub.lua

找到后执行文件,返回值存入 package.loaded"mod.sub"

相关推荐
星空露珠6 小时前
迷你世界UGc3.0脚本Wiki[剧情动画模块管理接口 Timeline]
开发语言·数据结构·算法·游戏·lua
xcLeigh8 小时前
Unity基础:Game视图详解——游戏预览、分辨率模拟与性能显示
游戏·unity·游戏引擎·音频·视频·game·play模式
开开心心_Every8 小时前
带OCR识别的电子发票打印工具
运维·自动化·ocr·电脑·powerpoint·音视频·lua
xcLeigh18 小时前
Unity基础:Scene视图操作完全指南——视角控制、物体选择与场景导航
unity·游戏引擎·scene·试图·场景导航
mxwin1 天前
Unity Shader exp 函数的算法与渲染应用
算法·unity·游戏引擎·shader
WarPigs1 天前
AB包自定义打包工具
unity
xingpanvip18 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
骇客之技术18 天前
AutoLua:在安卓上写 Lua 脚本
android·junit·lua
叶帆18 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君18 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型