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"

相关推荐
KindSuper_liu2 分钟前
Unity 游戏网络基础:从 TCP、UDP 到 HTTP、TLS 与 Best HTTP
网络·游戏·unity
还是大剑师兰特20 小时前
Unity3D(Unity)完整详细介绍
unity·游戏引擎
ellis19701 天前
u3d插件xLua[七]例6 Coroutine
unity
还是大剑师兰特1 天前
Unity 从零搭建简易3D场景(新手分步教程)
3d·unity·游戏引擎
神码编程1 天前
【Unity】TankBattle联机坦克大战(三)创建关卡(生成地块)
unity·游戏引擎·帧同步·坦克大战
淡海水1 天前
C#与常用数据结构源码剖析-全篇导览
开发语言·数据结构·unity·面试·职场和发展·c#
rockey6272 天前
基于AScript的Lua脚本语言发布啦
c#·.net·lua·script·动态脚本
玖玥拾2 天前
Unity3D RPG 入门项目(四)背包拖拽、物品悬浮提示、项目开发思维
3d·unity·游戏引擎
xcLeigh2 天前
Unity基础:Start与Update方法——Unity脚本生命周期初探
java·unity·游戏引擎·教程
郝学胜-神的一滴2 天前
[简化版 GAMES 104] 现代游戏引擎 05:游戏引擎世界构建核心机制深度解析
c++·程序人生·unity·游戏引擎·计算机图形学·opengl