Skip to content

模块与包

模块是 Lua 中用于组织代码的方式,它允许我们将相关的函数和变量封装在一起,以便于重用。本章节将介绍 Lua 中模块的定义、加载和使用方法。

模块的定义

在 Lua 中,模块通常是一个表,其中包含函数和变量:

lua
-- mymodule.lua
local M = {}

function M.add(a, b)
  return a + b
end

function M.sub(a, b)
  return a - b
end

M.pi = 3.1415926535898

return M

模块的加载

使用 require 函数加载模块:

lua
local mymodule = require("mymodule")
print(mymodule.add(10, 5))  -- 输出 15
print(mymodule.sub(10, 5))  -- 输出 5
print(mymodule.pi)  -- 输出 3.1415926535898

模块的搜索路径

当使用 require 加载模块时,Lua 会在以下路径中搜索模块:

  1. 环境变量 LUA_PATH 指定的路径
  2. Lua 安装目录中的 lua 文件夹
  3. 当前工作目录

LUA_PATH 的默认值通常是:

./?.lua;./?/init.lua;/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua

模块的组织

单文件模块

最简单的模块是一个单独的 .lua 文件,如前面的 mymodule.lua 示例。

目录模块

对于较大的模块,可以将其组织为一个目录,目录中包含一个 init.lua 文件:

mymodule/
  init.lua
  utils.lua
  constants.lua

init.lua 文件会被自动加载:

lua
-- mymodule/init.lua
local M = {}

M.utils = require("mymodule.utils")
M.constants = require("mymodule.constants")

function M.add(a, b)
  return a + b
end

return M

模块的访问控制

私有成员

在模块内部,可以使用局部变量和函数来创建私有成员:

lua
-- mymodule.lua
local M = {}

-- 私有函数
local function privateFunction()
  print("This is a private function")
end

-- 公共函数
function M.publicFunction()
  privateFunction()
  print("This is a public function")
end

return M

公共成员

模块返回的表中的成员都是公共的:

lua
local mymodule = require("mymodule")
mymodule.publicFunction()  -- 输出 This is a private function
                           -- 输出 This is a public function

mymodule.privateFunction()  -- 报错,因为 privateFunction 是私有的

模块的重命名

使用 require 加载模块时,可以给模块起一个别名:

lua
local mm = require("mymodule")
print(mm.add(10, 5))  -- 输出 15

模块的重载

默认情况下,require 会缓存已加载的模块,再次调用 require 时会返回缓存的模块:

lua
local m1 = require("mymodule")
local m2 = require("mymodule")
print(m1 == m2)  -- 输出 true,因为它们是同一个模块

如果需要重新加载模块,可以先从 package.loaded 中删除模块,然后再次调用 require

lua
package.loaded["mymodule"] = nil
local m3 = require("mymodule")
print(m1 == m3)  -- 输出 false,因为 m3 是重新加载的模块

标准库模块

Lua 提供了多个标准库模块:

  • math:数学函数
  • string:字符串操作
  • table:表操作
  • io:输入/输出操作
  • os:操作系统接口
  • debug:调试接口
  • coroutine:协同程序

示例:使用 math 模块

lua
print(math.pi)  -- 输出 3.1415926535898
print(math.sqrt(16))  -- 输出 4
print(math.sin(math.pi / 2))  -- 输出 1

示例:使用 string 模块

lua
local str = "Hello World"
print(string.upper(str))  -- 输出 HELLO WORLD
print(string.sub(str, 1, 5))  -- 输出 Hello

示例:使用 table 模块

lua
local t = {3, 1, 4, 1, 5}
table.sort(t)
for i, v in ipairs(t) do
  print(v)
end

第三方模块

Lua 有丰富的第三方模块,可以通过 LuaRocks 包管理器安装:

bash
luarocks install luasocket

安装后,可以使用 require 加载第三方模块:

lua
local socket = require("socket")
print(socket._VERSION)

模块的应用

示例 1:创建一个数学工具模块

lua
-- mathutils.lua
local M = {}

function M.add(a, b)
  return a + b
end

function M.sub(a, b)
  return a - b
end

function M.mul(a, b)
  return a * b
end

function M.div(a, b)
  if b == 0 then
    error("Division by zero")
  end
  return a / b
end

function M.pow(a, b)
  return a ^ b
end

function M.sqrt(a)
  return math.sqrt(a)
end

return M

示例 2:创建一个字符串工具模块

lua
-- stringutils.lua
local M = {}

function M.trim(str)
  return str:gsub("^%s*", ""):gsub("%s*$", "")
end

function M.split(str, sep)
  local t = {}
  for word in str:gmatch("([^" .. sep .. "]+)") do
    table.insert(t, word)
  end
  return t
end

function M.startsWith(str, prefix)
  return str:sub(1, #prefix) == prefix
end

function M.endsWith(str, suffix)
  return str:sub(-#suffix) == suffix
end

return M

小结

本章节介绍了 Lua 中模块的定义、加载、搜索路径、组织、访问控制、重命名、重载,以及标准库模块和第三方模块的使用。掌握这些内容,对于编写 Lua 程序非常重要。