第1章 - 模块与包管理
嗨,朋友!我是长安。
写过 Java 的你一定对 package 和 import 非常熟悉。Lua 也有自己的模块系统,虽然没有 Java 那么严格,但足够灵活。
🤔 什么是模块?
在 Java 中,你用 package 和 class 来组织代码。在 Lua 中,一个文件就是一个模块,通过 require 来加载。
| 概念 | Java | Lua |
|---|---|---|
| 模块定义 | package + class | 一个 .lua 文件 |
| 导入 | import xxx.yyy | require("xxx") |
| 导出 | public 关键字 | return 一个 Table |
| 包管理 | Maven / Gradle | LuaRocks |
📦 创建模块
创建一个工具模块
-- utils.lua
local M = {} -- 模块表
function M.add(a, b)
return a + b
end
function M.sub(a, b)
return a - b
end
function M.formatName(firstName, lastName)
return lastName .. firstName
end
-- 私有函数(不放到 M 表中,外部无法访问)
local function validate(value)
return value ~= nil
end
function M.safePrint(value)
if validate(value) then
print(value)
else
print("nil value")
end
end
return M -- 返回模块表
使用模块
-- main.lua
local utils = require("utils")
print(utils.add(3, 5)) -- 8
print(utils.sub(10, 3)) -- 7
print(utils.formatName("安", "长")) -- 长安
utils.safePrint("Hello") -- Hello
utils.safePrint(nil) -- nil value
Java 对比
// Utils.java
public class Utils {
public static int add(int a, int b) {
return a + b;
}
public static int sub(int a, int b) {
return a - b;
}
private static boolean validate(Object value) {
return value != null;
}
}
// Main.java
import com.example.Utils;
public class Main {
public static void main(String[] args) {
System.out.println(Utils.add(3, 5)); // 8
}
}
🔒 模块的私有与公开
-- mymodule.lua
local M = {}
-- 公开的(放入 M 表)
function M.publicMethod()
print("我是公开方法")
end
-- 私有的(local 函数,不放入 M 表)
local function privateMethod()
print("我是私有方法")
end
-- 公开方法可以调用私有方法
function M.doSomething()
privateMethod() -- 内部可以调用
print("做了一些事情")
end
return M
类比 Java
- 放入
M表中的函数 →public方法 local函数不放入M表 →private方法- 模块表
M→ Java 类
📂 模块路径
require 会在一系列路径中查找模块:
-- 查看模块搜索路径
print(package.path)
-- 通常输出类似:
-- ./?.lua;/usr/local/share/lua/5.4/?.lua;...
-- ? 会被替换为模块名
-- require("utils") 会依次查找:
-- ./utils.lua
-- /usr/local/share/lua/5.4/utils.lua
-- ...
子目录模块
-- 文件结构:
-- project/
-- ├── main.lua
-- └── lib/
-- └── json.lua
-- 加载子目录模块
local json = require("lib.json") -- 用 . 分隔目录
注意
Lua 用 . 作为路径分隔符(不是 /),这和 Java 的 import com.example.Utils 类似。
🔄 require 的缓存机制
require 加载模块后会缓存结果,多次 require 同一个模块只会执行一次:
-- 第一次加载:执行模块代码
local m1 = require("mymodule")
-- 第二次加载:直接返回缓存,不会重新执行
local m2 = require("mymodule")
print(m1 == m2) -- true(是同一个对象)
-- 如果需要强制重新加载:
package.loaded["mymodule"] = nil -- 清除缓存
local m3 = require("mymodule") -- 重新执行
Java 对比
这和 Java 的类加载器缓存机制类似——一个类只会被加载一次(除非用不同的 ClassLoader)。
📦 LuaRocks — Lua 的包管理器
LuaRocks 之于 Lua,就像 Maven 之于 Java:
# 安装 LuaRocks
# macOS
brew install luarocks
# 安装一个包
luarocks install luasocket
luarocks install lua-cjson
# 查看已安装的包
luarocks list
# 搜索包
luarocks search json
| 操作 | Maven (Java) | LuaRocks (Lua) |
|---|---|---|
| 安装依赖 | mvn install | luarocks install xxx |
| 搜索包 | mvnrepository.com | luarocks search xxx |
| 配置文件 | pom.xml | .rockspec |
| 仓库 | Maven Central | luarocks.org |
📝 小结
- 一个 Lua 文件就是一个模块,通过
return导出 - 用
require("模块名")导入模块 local函数 = 私有,放入模块表 = 公开require有缓存机制,多次调用不会重复执行- LuaRocks 是 Lua 的包管理器,类似 Maven
➡️ 下一步
模块化搞定了!下一章来学习 文件 I/O 操作。
💪 练习题
- 创建一个
math_utils.lua模块,包含square(x)和cube(x)两个公开函数。 - 在另一个文件中
require并调用这两个函数。 - 如何在模块中实现"私有"函数?
require的缓存机制是什么?如何强制重新加载?
答案提示
local M = {} function M.square(x) return x*x end function M.cube(x) return x*x*x end return Mlocal mu = require("math_utils") print(mu.square(5))- 用
local function定义,不放入模块表M中 - 首次加载后缓存结果,
package.loaded["xxx"] = nil清除缓存
