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"

相关推荐
淡海水2 小时前
38-Hybrid生态-LeanCLR总览
unity·架构·c#·热更新·clr·hybrid·leanclr
塵觴葉3 小时前
基于Lua协程的简单任务管理
开发语言·lua
郝学胜-神的一滴4 小时前
[简化版 GAMES 101] 计算机图形学 13:从光栅化到着色——赋予三维像素光影灵魂
c++·计算机视觉·unity·godot·图形渲染·opengl·unreal
fqkw64 小时前
unity 安装MCP +uvx
unity·游戏引擎
魔士于安20 小时前
unity 音乐会场景 unity2022
游戏·unity·游戏引擎·贴图·模型
Mediary1 天前
Unity is running with Administrator privileges, which isnot supported...
unity
游乐码1 天前
Unity基础(十四)场景异步加载
unity·游戏引擎
mxwin1 天前
Unity Shader URP:法线在空间变换上的特殊性
unity·游戏引擎·shader
nnsix1 天前
Unity 动态批处理、静态批处理、GPU Instaning、SRP Batcher 笔记
笔记·unity·单一职责原则