Lua 模块与包

本文详细介绍了 Lua 中的模块概念,包括模块的加载流程、require 函数的工作原理、搜索器的使用、模块的编写与子模块的处理。重点讨论了 require 如何通过 package.loaded、preload、Lua 和 C 搜索器查找模块,并提供了示例代码演示模块的加载和自定义搜索器。此外,还介绍了模块的返回值、搜索路径以及如何处理模块重命名和子模块的关联。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是模块

模块就是一些代码(可以是 Lua 编写的,也可以是 C 语言编写的),这些代码可以通过函数 require 加载,然后创建和返回一个表,这个表就类似命名空间。

所有的标准库都是模块,例如 mathstring 模块

使用表来承载模块,有很显著的优点,可以像操作普通表一样操作模块,而且能利用 Lua 语言的所有功能实现额外的功能。

例如引入 math 模块

-- 两种书写方式都可以使用
local math = require "math"
--local math = require("math")

-- sin 使用的是弧度,不是角度
print(math.sin(3.14))

也可以直接引入模块中的一个函数,例如以下代码

直接引入模块中的函数,实际上只是省去了模块这一中间变量,从加载的模块 table 中获取相应的 value

-- 引用模块中的某个函数
-- 等同于 require("math").sin
-- 此时 require("math") 获取到了引入表,`.sin` 即从表中获取了对应的值 value ,此时为一个函数
local sin = require "math".sin
print(sin(3.14))

二、require(modname)

Lua 通过 require(modname) 函数进行加载模块,modname 为需要加载的模块名(字符串类型)。

0、require 函数加载模块的流程

require 会先从 package.loaded 中获取,如果没有找到相应模块,则进入根据搜索器列表 package.searches 中设置的搜索器按顺序进行查找。

package.searches 默认内置了 4 个搜索器,按顺序分别为 预加载搜索器Lua 搜索器C 标准库搜索器C 库子模块搜索器

假设我们使用了 require('A') 进行加载 A 模块,会进行以下加载步骤:

1、第一步:会在 package.loaded 中检查模块 “A” 是否已经存在,如果存在则会将其返回,不存在则进入第二步骤

package.loaded 是一个 table , 存储着加载成功的模块,以模块名为 key ,模块返回结果为 value 的形式存放。

如果 package.loaded 不存在对应的模块,则会进入到后续的步骤进行搜索,无论后续的哪一步骤让模块加载成功,都会将模块的返回值(该返回值类型可以是 function 、 table 等数据类型)作为 value 和加载的模块名(例如这里的 A )为 key ,以 key-value 的形式存放到 package.loaded table 中。如果模块没有返回值,则会用 true 代替返回值,从而达到不会每次加载相同模块都需要运行一次加载流程。

举个例子

加载两个模块,然后通过打印 package.loaded 查看已经加载的模块

print("package.loaded 已经加载的模块:")

-- 获取当前 lua 的文件夹路径
local currentPath = debug.getinfo(1, "S").source:sub(2):match("(.*/)")
-- 设置加载模块路径
package.path = package.path .. ";" .. currentPath .. "../?.lua"

require("一个合理的模块")
require("module.sub")

for path, package in pairs(package.loaded) do
    print("----- 模块【" .. path .. "】包含的属性:-----")
    if type(package) == "table" then
        for key, value in pairs(package) do
            print(key, "---", value)
        end
    else
        print(path, "---", package)
    end
    print("--------------------------------")
end

打印的内容会比较多,因为 Lua 默认加载的函数也会在其中,但在众多的输出中,可以找到加载的 “一个合理的模块” 和 “module.sub” 模块(见下图)

“一个合理的模块” 模块会返回一个 table ,所以会将 table 存储在 package.loaded 表中(这里输出的便是存储的内容)。

具体代码可以进入 github 查看 https://github.com/zincPower/lua_study_2022/blob/master/11%20%E6%A8%A1%E5%9D%97%E5%92%8C%E5%8C%85/%E4%B8%80%E4%B8%AA%E5%90%88%E7%90%86%E7%9A%84%E6%A8%A1%E5%9D%97.lua

“module.sub” 模块则没有返回值,所以 Lua 会默认返回 true ,将其存储在 pacakge.loaded 表中(从输出的内容也可以验证这一点)。

具体代码可以进入 github 查看 https://github.com/zincPower/lua_study_2022/blob/master/11%20%E6%A8%A1%E5%9D%97%E5%92%8C%E5%8C%85/module/sub.lua

2、第二步:在 “预加载搜索器” 中使用 package.preload 查找是否有对应加载函数,如果有则会将加载函数返回,否则进入第三步骤

package.preload 也是一个 table ,只是他的 value 必须是一个加载函数。

会根据 require 传入的模块名,在 preload 中查询,如果找到对应的 key ,则调用 value(是一个函数),会将请求的模块名和加载的来源(这里是通过预加载器,即 preload)传递给 value 函数,最后会将该函数的返回值作为模块的返回值存储在第一步提到的 package.loaded 中, 方便后续加载相同的模块。

可以运行代码,通过调用 showLoadedModule 函数,感受这一过程

print("package.preload:")

local function 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值