第4章:状态与模块
一、导读
1.1 本章学习目标
第4章讲解 Lua 的模块化编程:模块、环境、全局变量。
本章核心学习目标:
- 掌握模块系统:require 和 module
- 理解环境(environment)
- 掌握全局变量的控制
1.2 为什么本章如此重要
模块化是组织大型 Lua 项目的基础。理解模块系统能写出可维护的代码。
1.3 核心问题引导
Lua 的模块本质上是什么?
require 如何查找和加载模块?
如何避免全局变量污染?
二、核心概念详解
2.1 模块
lua
-- mylib.lua
local M = {}
local private_var = "secret"
function M.public_func()
return "public"
end
function M.another_func()
return private_var -- 可以访问局部变量
end
return M
-- main.lua
local mylib = require("mylib")
print(mylib.public_func()) -- public
print(mylib.private_var) -- nil (不可访问)2.2 require 机制
lua
-- require 的工作流程:
-- 1. 检查 package.loaded[modname]
-- 2. 如果不存在,查找 package.path
-- 3. 加载并执行模块文件
-- 4. 将返回值存入 package.loaded[modname]
-- package.path 示例
print(package.path)
-- ./?.lua;./?/init.lua;/usr/local/share/lua/5.4/?.lua;...
-- 加载 C 模块
-- package.cpath 控制 C 模块的搜索路径
-- 重新加载模块
package.loaded["mylib"] = nil
local mylib = require("mylib") -- 重新加载2.3 全局变量控制
lua
-- 检测未声明的全局变量
setmetatable(_G, {
__newindex = function(t, n, v)
if not rawget(t, "_declared") then
rawget(t, "_declared")[n] = true
end
rawset(t, n, v)
end,
__index = function(t, n)
if not rawget(t, "_declared") or not rawget(t, "_declared")[n] then
error("attempt to read undeclared variable: " .. n, 2)
end
end
})
-- 声明全局变量
function declare(name, initval)
rawset(_G, name, initval or false)
if not rawget(_G, "_declared") then
rawset(_G, "_declared", {})
end
rawget(_G, "_declared")[name] = true
end三、实战案例
3.1 案例一:配置管理模块
lua
-- config.lua
local M = {}
local config = {
debug = false,
log_level = "info",
max_connections = 100,
}
function M.get(key)
return config[key]
end
function M.set(key, value)
config[key] = value
end
function M.load(filename)
local f = loadfile(filename)
if f then
local user_config = f()
for k, v in pairs(user_config) do
config[k] = v
end
end
end
return M
-- 使用
local config = require("config")
config.load("settings.lua")
print(config.get("debug"))四、本章小结
模块是返回 table 的文件
require 缓存已加载的模块
避免全局变量,使用模块封装
五、思考与练习
如何实现模块的延迟加载?
如何防止模块被重复加载?