模块基础 #

一、模块概述 #

1.1 什么是模块 #

模块是 Lua 组织代码的基本方式,一个模块就是一个返回表的 Lua 文件:

lua
-- mymodule.lua
local M = {}

M.version = "1.0"

function M.hello()
    print("Hello from module!")
end

return M

1.2 模块的优势 #

  • 代码组织:将相关功能组织在一起
  • 命名空间:避免全局命名冲突
  • 复用性:代码可以在多个项目中复用
  • 封装性:隐藏实现细节

二、创建模块 #

2.1 基本模块 #

lua
-- math_utils.lua
local M = {}

M.PI = 3.14159

function M.square(x)
    return x * x
end

function M.cube(x)
    return x * x * x
end

function M.distance(x1, y1, x2, y2)
    local dx = x2 - x1
    local dy = y2 - y1
    return math.sqrt(dx * dx + dy * dy)
end

return M

2.2 私有成员 #

lua
-- counter.lua
local M = {}

-- 私有变量
local count = 0

-- 私有函数
local function validate(n)
    return type(n) == "number" and n >= 0
end

-- 公共接口
function M.increment(n)
    n = n or 1
    if validate(n) then
        count = count + n
    end
end

function M.get()
    return count
end

function M.reset()
    count = 0
end

return M

2.3 模块定义方式 #

lua
-- 方式1:返回表(推荐)
local M = {}
function M.func() end
return M

-- 方式2:直接返回
return {
    func = function() end
}

-- 方式3:使用 module 函数(已弃用)
-- module("mymodule", package.seeall)

三、加载模块 #

3.1 require 函数 #

lua
-- 加载模块
local math_utils = require("math_utils")

-- 使用模块
print(math_utils.PI)
print(math_utils.square(5))
print(math_utils.distance(0, 0, 3, 4))

3.2 require 的工作原理 #

lua
-- require 的执行过程:
-- 1. 检查 package.loaded 表,如果已加载则返回缓存
-- 2. 搜索模块文件
-- 3. 编译并执行模块代码
-- 4. 将返回值存入 package.loaded
-- 5. 返回模块

-- 查看已加载的模块
for name, module in pairs(package.loaded) do
    print(name, module)
end

3.3 模块搜索路径 #

lua
-- 查看搜索路径
print(package.path)   -- Lua 模块路径
print(package.cpath)  -- C 模块路径

-- 修改搜索路径
package.path = package.path .. ";./my_modules/?.lua"

3.4 模块搜索器 #

lua
-- 查看搜索器列表
for i, searcher in ipairs(package.searchers) do
    print(i, searcher)
end

-- 搜索器执行顺序:
-- 1. package.preload 预加载表
-- 2. Lua 模块搜索器
-- 3. C 模块搜索器
-- 4. C 根模块搜索器

四、模块路径 #

4.1 路径格式 #

lua
-- package.path 中的占位符
-- ?  表示模块名
-- ;  分隔多个路径

-- 示例路径
-- ./?.lua
-- /usr/local/share/lua/5.4/?.lua
-- /usr/local/share/lua/5.4/?/init.lua

-- 加载 foo.bar 模块
-- 会搜索:./foo/bar.lua
local foo_bar = require("foo.bar")

4.2 设置路径 #

lua
-- 方法1:修改 package.path
package.path = "./lib/?.lua;./src/?.lua;" .. package.path

-- 方法2:设置环境变量
-- LUA_PATH="./lib/?.lua;;"
-- LUA_CPATH="./lib/?.so;;"

-- 方法3:在代码中设置
local function add_path(path)
    package.path = path .. "/?.lua;" .. package.path
    package.path = path .. "/?/init.lua;" .. package.path
end

五、模块模式 #

5.1 单例模式 #

lua
-- singleton.lua
local Singleton = {}

local instance = nil

function Singleton.get_instance()
    if not instance then
        instance = {
            value = 0,
            increment = function(self)
                self.value = self.value + 1
            end
        }
    end
    return instance
end

return Singleton

5.2 类模式 #

lua
-- person.lua
local Person = {}
Person.__index = Person

function Person.new(name, age)
    return setmetatable({
        name = name,
        age = age
    }, self)
end

function Person:greet()
    print("Hello, I'm " .. self.name)
end

function Person:get_age()
    return self.age
end

return Person

5.3 命名空间模式 #

lua
-- myapp.lua
local MyApp = {}

MyApp.version = "1.0"

-- 子模块
MyApp.utils = require("myapp.utils")
MyApp.config = require("myapp.config")
MyApp.models = require("myapp.models")

return MyApp

六、模块重载 #

6.1 强制重载 #

lua
-- 清除模块缓存
package.loaded["mymodule"] = nil

-- 重新加载
local mymodule = require("mymodule")

6.2 热重载 #

lua
local function reload_module(name)
    package.loaded[name] = nil
    return require(name)
end

-- 开发时使用
local mymodule = reload_module("mymodule")

七、模块组织 #

7.1 目录结构 #

text
myproject/
├── main.lua
└── lib/
    ├── myapp/
    │   ├── init.lua      -- myapp 模块入口
    │   ├── utils.lua     -- myapp.utils
    │   ├── config.lua    -- myapp.config
    │   └── models/
    │       ├── init.lua  -- myapp.models
    │       └── user.lua  -- myapp.models.user
    └── thirdparty/
        └── json.lua

7.2 init.lua 模式 #

lua
-- lib/myapp/init.lua
local M = {}

M.utils = require("myapp.utils")
M.config = require("myapp.config")
M.models = require("myapp.models")

M.version = "1.0"

return M

-- 使用
local myapp = require("myapp")
myapp.utils.helper()

八、最佳实践 #

8.1 模块命名 #

lua
-- 使用小写字母和点分隔
-- myapp.utils.string
-- myapp.models.user

-- 避免使用下划线
-- myapp_utils_string(不推荐)

8.2 模块文档 #

lua
--[[
    模块名:math_utils
    描述:数学工具函数
    版本:1.0.0
    作者:Your Name
    
    用法:
        local math_utils = require("math_utils")
        print(math_utils.square(5))
]]

local M = {}

M.version = "1.0.0"

return M

8.3 错误处理 #

lua
local M = {}

function M.divide(a, b)
    if b == 0 then
        return nil, "除数不能为零"
    end
    return a / b
end

-- 使用
local result, err = M.divide(10, 0)
if not result then
    print("错误:" .. err)
end

九、总结 #

本章介绍了 Lua 模块的基础知识:

  1. 模块概念:组织代码的基本方式
  2. 创建模块:返回表的 Lua 文件
  3. 加载模块:require 函数的使用
  4. 模块路径:搜索路径和设置
  5. 模块模式:单例、类、命名空间
  6. 模块组织:目录结构和最佳实践

下一章,我们将学习包管理。

最后更新:2026-03-27