Lua 模块
Lua - 模块
Section titled “Lua - 模块”什么是模块?
Section titled “什么是模块?”在 Lua 中,模块本质上是一个库(library),它提供了一系列函数和变量,通常封装在一个表中。这个表充当一个命名空间(namespace),防止与代码的其他部分或其他模块发生命名冲突。模块使用 require 函数加载,该函数通常返回这个表,允许你访问其内容。
Lua 模块的特性
Section titled “Lua 模块的特性”使用表作为模块提供了显著的灵活性,允许像操作其他任何 Lua 表一样操作模块。这种动态特性意味着 Lua 不需要特殊的语言结构来实现其他语言可能需要的功能。你可以通过多种方式与模块函数交互:
-- 假设我们有一个名为 'printFormatter.lua' 的模块-- 并且 printFormatter.lua 包含一个函数 simpleFormat(arg)
-- Method 1: Direct access after require-- 方法 1:require 后直接访问require "printFormatter"printFormatter.simpleFormat("test")
-- Method 2: Assign the returned module table to a local variable (recommended)-- 方法 2:将返回的模块表赋值给局部变量(推荐)local formatter = require "printFormatter"formatter.simpleFormat("test")
-- Method 3: Get a direct reference to a function from the module-- 方法 3:从模块获取函数的直接引用local formatterFunction = require("printFormatter").simpleFormatformatterFunction("test")
-- Method 4: If the module is already loaded and assigned-- 方法 4:如果模块已加载并赋值local myFormatter = require "printFormatter"local sf = myFormatter.simpleFormat -- Local alias for brevity-- 局部别名,用于简化sf("another test")这些示例展示了 Lua 在模块使用方面的灵活方法,无需复杂的语法。
require 函数
Section titled “require 函数”Lua 提供了 require 函数来加载模块。当你调用 require("modulename") 时,Lua 会在预定义的路径序列中搜索该模块。对于 Lua 文件,它检查 package.path;对于 C 库,它检查 package.cpath。require 函数是智能的:它只加载模块一次。后续对同一模块的 require 调用将返回第一次调用缓存的值。模块应是一个代码块(chunk of code),它定义了一些值(通常是函数或包含函数的表),并且最重要的是,返回一个单一值(通常是模块表本身)。
示例:创建并使用模块
Section titled “示例:创建并使用模块”让我们创建一个名为 mymath.lua 的简单数学模块。模块中的函数最好返回值而不是直接打印,这样可以使模块更具可重用性。
-- File: mymath.lua-- 文件:mymath.lualocal mymath = {}
-- It's good practice to make module functions local if they are helpers,-- 将模块函数设为 local 是个好习惯,如果它们是助手函数-- or attach them directly to the module table if they are public.-- 或者如果它们是公共接口,则直接附加到模块表。function mymath.add(a, b) return a + bend
function mymath.subtract(a, b) return a - bend
function mymath.multiply(a, b) return a * bend
function mymath.divide(a, b) if b == 0 then return nil, "Error: Division by zero" end return a / bend
return mymath要在另一个 Lua 文件中使用此模块,比如 main.lua(确保这两个文件位于同一目录中,或者 mymath.lua 在 Lua 的包路径中):
-- File: main.lua-- 文件:main.lualocal mymathmodule = require("mymath")
print("Addition (10, 20):", mymathmodule.add(10, 20)) -- Expected: 30-- 加法 (10, 20): 期望值:30print("Subtraction (30, 20):", mymathmodule.subtract(30, 20)) -- Expected: 10-- 减法 (30, 20): 期望值:10print("Multiplication (10, 20):", mymathmodule.multiply(10, 20))-- Expected: 200-- 乘法 (10, 20): 期望值:200
local result, err = mymathmodule.divide(30, 20)if err then print(err)else print("Division (30, 20):", result) -- Expected: 1.5 -- 除法 (30, 20): 期望值:1.5end
local result2, err2 = mymathmodule.divide(5, 0)if err2 then print(err2) -- Expected: Error: Division by zero -- 期望值:错误:除数为零else print("Division (5,0):", result2)end当你运行 lua main.lua 时,输出将是:
Addition (10, 20): 30Subtraction (30, 20): 10Multiplication (10, 20): 200Division (30, 20): 1.5Error: Division by zero模块的关键实践
Section titled “模块的关键实践”- 将模块文件放在 Lua 可以找到它们的位置(与主脚本在同一目录,或位于
package.path中列出的目录)。 - 在
require("modulename")中使用的模块名应与文件名对应(例如modulename.lua)。 - 标准且推荐的做法是模块返回一个包含其公共接口的表。
- 如果模块函数和变量不属于公共接口,则将其声明为
local,以促进封装(encapsulation)。
过时的模块实现(module() 函数)
Section titled “过时的模块实现(module() 函数)”在 Lua 的旧版本(主要是 Lua 5.1)中,模块有时使用 module("name", package.seeall) 函数定义。这种方法现已废弃且强烈不推荐。它会污染全局命名空间(global namespace)并带来其他不良副作用。
-- Old, deprecated way (mymath_old.lua)-- 旧的、已废弃的方式 (mymath_old.lua)module("mymath_old", package.seeall)
function add(a, b) -- Note: this becomes a global function! -- 注意:这会成为一个全局函数! print(a + b)end
function sub(a, b) print(a - b)end-- ... and so on for mul and div-- ... mul 和 div 类似使用这种旧式模块:
-- main_old.luarequire("mymath_old")
-- Functions from mymath_old are now global or accessed via the global table mymath_old-- 来自 mymath_old 的函数现在是全局的,或者通过全局表 mymath_old 访问-- This depends on the exact behavior of the `module` function version used.-- 这取决于使用的 `module` 函数版本的具体行为。-- For example, you might call add(10, 20) directly.-- 例如,你可以直接调用 add(10, 20)。mymath_old.add(10,20)mymath_old.sub(30,20)虽然你可能在遗留代码中遇到这种模式,但新项目应始终使用返回表的现代方法。module() 函数已在 Lua 5.2 中移除。这种旧式风格安全性较低,管理更困难,并且与当前模块化设计的最佳实践相悖。