Модули и require
Учимся разбивать программу на переиспользуемые файлы-модули.
Модуль — это отдельный файл Lua, который возвращает таблицу с функциями, чтобы другие файлы могли её подключить и использовать.
Когда программа растёт, держать весь код в одном файле невозможно. Модули позволяют разложить логику по файлам: математика в одном, графика в другом.
Создание модуля
Модуль — это файл, который собирает свои функции в таблицу и возвращает её через return. Пусть это файл mathutils.lua:
-- файл mathutils.lua
local M = {}
function M.double(x)
return x * 2
end
function M.half(x)
return x / 2
end
return MГлавное — последняя строка return M: она отдаёт таблицу наружу.
Подключение через require
В другом файле подключаем модуль функцией require (без расширения .lua):
-- файл main.lua
local mathutils = require("mathutils")
print(mathutils.double(21))
print(mathutils.half(10))Вывод:
42 5
require ищет файл, исполняет его и возвращает то, что тот вернул — нашу таблицу M.
Кэширование модулей
Важная особенность: модуль исполняется только один раз. Повторный require того же модуля вернёт уже готовый результат из кэша:
local a = require("mathutils")
local b = require("mathutils")
-- a и b — это одна и та же таблицаЭто удобно: тяжёлая настройка внутри модуля выполнится один раз, сколько бы файлов его ни подключали.
Схема модульной структуры
main.lua
├─ require("mathutils") ──> mathutils.lua (return M)
└─ require("graphics") ──> graphics.lua (return G)Как работает под капотом
Lua хранит загруженные модули в таблице package.loaded. При вызове require("mathutils") сначала проверяется, нет ли модуля там; если есть — возвращается готовый. Если нет — файл ищется по путям из package.path, исполняется, а результат кладётся в кэш.
Частые ошибки
- Писать
require("mathutils.lua")с расширением — нужно без него. - Забыть
return Mв конце модуля — тогдаrequireвернётtrueвместо таблицы. - Ждать, что модуль перечитается при втором
require— он берётся из кэша.
Итог
- Модуль — файл, собирающий функции в таблицу и возвращающий её через
return. require("имя")подключает модуль без расширения и возвращает его таблицу.- Модули кэшируются: исполняются один раз, повторный
requireотдаёт готовое. - Загруженные модули хранятся в
package.loaded.