Шаблоны модулей и рекомендации
Используйте шаблон local M = {} и аккуратно предоставляйте публичный программный интерфейс.
«Шаблоны модулей и рекомендации» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.
Шаблон M = {}
Универсальный шаблон модуля Lua: объявите локальную таблицу, заполните её и верните. Все открытые символы помещаются в M, а все закрытые вспомогательные элементы являются обычными локальными элементами. Этот подход понятен, минимален и работает повсюду.
-- The canonical module pattern
local M = {}
-- Private helper (not exported)
local function validate(x)
return type(x) == "number" and x >= 0
end
-- Public API
function M.sqrt(x)
assert(validate(x), "expected non-negative number")
return math.sqrt(x)
end
M.PI = math.pi
return MМодуль со ссылками на самого себя
Внутри модуля функции могут вызывать другие функции модуля либо по имени (M.foo()), либо как локальные элементы. Использование локальных элементов немного быстрее; использование M.foo() позволяет пользователям переопределить M.foo, после чего внутренний вызов будет использовать переопределённую версию (изменение кода во время работы).
local M = {}
-- Option A: use M.foo inside (allows override)
function M.double(n) return M.multiply(n, 2) end
function M.multiply(a, b) return a * b end
-- Option B: use local function (faster, no override)
local function mul(a, b) return a * b end
function M.triple(n) return mul(n, 3) end
return MШаблон одиночки
Модуль может работать как одиночка: он содержит изменяемое внутреннее состояние, общее для всех вызывающих объектов. Поскольку require кэширует модуль, все вызовы require("mod") получают один и тот же объект с одним и тем же состоянием.
-- config.lua (singleton)
local M = {}
local _config = {env="dev", logLevel="info"}
function M.set(key, val)
_config[key] = val
end
function M.get(key)
return _config[key]
end
function M.load(t)
for k,v in pairs(t) do _config[k]=v end
end
return M
-- All callers share the same config:Модуль как пространство имён
Используйте модуль только как пространство имён, чтобы не засорять глобальную таблицу. Объединяйте связанные константы и вспомогательные средства под одним именем, подобно пакету в других языках.
-- constants.lua
local M = {
HTTP = {
OK=200, CREATED=201, NO_CONTENT=204,
BAD_REQUEST=400, UNAUTHORIZED=401,
NOT_FOUND=404, SERVER_ERROR=500,
},
COLORS = {RED="#FF0000", GREEN="#00FF00", BLUE="#0000FF"},
MAX_RETRIES = 3,
TIMEOUT_SEC = 30,
}
return M
-- local C = require("constants")
-- if status == C.HTTP.NOT_FOUND then ...Модуль-фабрика
Такой модуль экспортирует функцию-фабрику вместо обычной таблицы. Фабрика создаёт и возвращает новые экземпляры с собственным закрытым состоянием. Это шаблон класса на уровне модуля.
-- logger.lua
local M = {}
function M.new(name, level)
level = level or "info"
local levels = {debug=1,info=2,warn=3,error=4}
local self = {}
function self.log(msgLevel, msg)
if levels[msgLevel] >= levels[level] then
print(string.format("[%s][%s] %s", name, msgLevel:upper(), msg))
end
end
function self.info(msg) self.log("info", msg) end
function self.warn(msg) self.log("warn", msg) end
function self.error(msg) self.log("error", msg) end
return self
end
return MФункция инициализации модуля
Некоторым модулям требуется конфигурация перед использованием. Предоставьте функцию M.init(config), которая сохранит конфигурацию в закрытом состоянии модуля. Это позволяет внедрять зависимости и упрощает тестирование.
-- db.lua
local M = {}
local pool = nil
function M.init(config)
pool = {
host = config.host or "localhost",
port = config.port or 5432,
connections = {},
}
print("DB initialized:", pool.host, pool.port)
end
function M.query(sql)
assert(pool, "call db.init() first")
-- ... execute query
return {}
end
return MНеизменяемый модуль
Предотвратите случайное изменение API модуля пользователями с помощью __newindex, блокируя все записи. Это особенно полезно для библиотечных модулей, где случайное изменение кода во время работы может нарушить их работу.
local function freeze(t)
return setmetatable({}, {
__index = t,
__newindex = function(_, k, _)
error("module is read-only, cannot set: " .. tostring(k), 2)
end
})
end
local M = {}
function M.add(a, b) return a + b end
function M.sub(a, b) return a - b end
return freeze(M)Документирование с помощью LDoc
Распространённое соглашение для документирования модулей Lua — комментарии в стиле LDoc с префиксом ---. Язык не требует их использования, но эти комментарии позволяют инструментам автоматической генерации создавать документацию API.
--- A utility module for string operations.
-- @module stringutils
local M = {}
--- Trim leading and trailing whitespace.
-- @param s string The input string.
-- @return string The trimmed string.
function M.trim(s)
return s:match("^%s*(.-)%s*$")
end
--- Count occurrences of a substring.
-- @param str string The string to search.
-- @param sub string The substring to count.
-- @return number Count of occurrences.
function M.count(str, sub)
local _, n = str:gsub(sub, "")
return n
end
return MТестирование модулей
Тестируйте модуль, загрузив его и проверив работу каждой функции. Используйте простой исполнитель тестов или busted (тестовую платформу Lua). Храните тесты в отдельном файле, соответствующем пути модуля.
-- test/test_stringutils.lua
local su = require("stringutils")
local function test(name, fn)
local ok, err = pcall(fn)
if ok then print("[PASS] " .. name)
else print("[FAIL] " .. name .. ": " .. err)
end
end
test("trim removes spaces", function()
assert(su.trim(" hello ") == "hello")
end)
test("trim empty string", function()
assert(su.trim("") == "")
end)
test("count occurrences", function()
assert(su.count("banana", "a") == 3)
end)Объединение модулей
Сложные системы объединяют несколько модулей. Главная точка входа загружает подмодули и связывает их между собой. Такое разделение ответственности позволяет каждому модулю оставаться специализированным и упрощает независимое тестирование.
-- app.lua (main entry point)
local config = require("config")
local db = require("db")
local server = require("server")
-- Configure from environment
config.load({
dbHost = os.getenv("DB_HOST") or "localhost",
port = tonumber(os.getenv("PORT")) or 8080,
})
-- Wire modules together
db.init({host=config.get("dbHost"), port=5432})
server.init({port=config.get("port"), db=db})
server.start()Быстрая проверка
Каково основное назначение шаблона модуля local M = {} ... return M?
Повторение: рекомендации по работе с модулями
Краткое содержание:
- Всегда используйте
local M = {} ... return M - Закрытые элементы = локальные элементы уровня файла; открытые элементы = поля M
- Одиночка: require кэширует экземпляр модуля
- Используйте функции-фабрики для состояния отдельных экземпляров
- Замораживайте модули с помощью __newindex, чтобы предотвратить изменения
- Проводите тестирование в отдельных файлах; документируйте код комментариями ---
Изучай Lua с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 40
- Уроки
- 159
Часто задаваемые вопросы
Урок «Шаблоны модулей и рекомендации» бесплатный?
Да — полный текст урока «Шаблоны модулей и рекомендации» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.
Чему я научусь в уроке «Шаблоны модулей и рекомендации»?
Используйте шаблон local M = {} и аккуратно предоставляйте публичный программный интерфейс. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Lua Academy?
Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Шаблоны модулей и рекомендации»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Lua Academy?
Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Функция require
- Создание файла модуля
- package.path и package.cpath
- Шаблоны модулей и рекомендации