Модули и пакеты в Lua
Модуль похож на инкапсулированную библиотеку. Начиная с Lua 5.1, в Lua добавлен стандартный механизм управления модулями, который позволяет размещать некоторый общий код в файле и вызывать его в другом месте в виде интерфейса API, что способствует повторному использованию кода и уменьшению связанности кода.
Модуль Lua — это таблица, состоящая из известных элементов, таких как переменные и функции. Поэтому создание модуля очень просто: создайте таблицу, поместите в неё константы и функции, которые нужно экспортировать, и в конце верните эту таблицу. Ниже показано создание пользовательского модуля module.lua. Формат кода файла следующий:
-- Определить модуль с именем module
module = {}
-- Определить константу
module.constant = "Это константа"
-- Определить функцию
function module.func1()
io.write("Это публичная функция!"\n")
end
local function func2()
print("Это приватная функция!")
end
function module.func3()
func2()
end
return module
Из вышесказанного следует, что структура модуля — это структура таблицы, поэтому вы можете работать с константами или функциями модуля и вызывать их так же, как работаете с элементами таблицы и вызываете их.
Указанная выше func2 объявлена как локальная переменная блока программы, что означает, что это приватная функция. Следовательно, к этой приватной функции в модуле нельзя получить доступ извне, и её нужно вызывать через публичную функцию в модуле.
Функция require
Lua предоставляет функцию require для загрузки модулей. Чтобы загрузить модуль, достаточно её вызвать. Например:
require("<模块名>")
Или
require "<模块名>"
После выполнения require возвращается таблица, состоящая из констант или функций модуля, а также определяется глобальная переменная, содержащая эту таблицу.
Файл test_module.lua
-- Модуль module — это module.lua, упомянутый выше
require("module")
print(module.constant)
module.func3()
Результат выполнения приведённого выше кода:
This is a constant This is a private function!
Или определите переменную-псевдоним для загруженного модуля для удобного вызова:
Файл test_module2.lua
-- Модуль module — это module.lua, упомянутый выше
-- Переменная-псевдоним m
local m = require("module")
print(m.constant)
m.func3()
Результат выполнения приведённого выше кода:
This is a constant This is a private function!
Механизм загрузки
Для пользовательских модулей файл модуля нельзя размещать в произвольном каталоге. Функция require имеет собственную стратегию загрузки по путям к файлам. Она попытается загрузить модуль из Lua-файла или библиотеки программы на C.
Путь, используемый require для поиска Lua-файлов, хранится в глобальной переменной package.path. При запуске Lua инициализирует эту переменную окружения значением переменной окружения LUA_PATH. Если эта переменная окружения не найдена, для инициализации используется путь по умолчанию, определённый во время компиляции.
Конечно, если переменной окружения LUA_PATH нет, можно также настроить параметры вручную. Откройте файл .profile в домашнем каталоге текущего пользователя (создайте его, если он не существует, или откройте файл .bashrc). Например, добавьте путь "~/lua/" в переменную окружения LUA_PATH:
#LUA_PATH export LUA_PATH="~/lua/?.lua;;"
Пути к файлам разделяются точкой с запятой ";". Последние 2 ";;" означают, что после вновь добавленного пути следует исходный путь по умолчанию.
Затем обновите параметры переменной окружения, чтобы изменения вступили в силу немедленно.
source ~/.profile
В этом случае предположим, что значение package.path равно:
/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua
Тогда при вызове require("module") она попытается открыть следующие каталоги файлов для поиска цели.
/Users/dengjoe/lua/module.lua; ./module.lua /usr/local/share/lua/5.1/module.lua /usr/local/share/lua/5.1/module/init.lua /usr/local/lib/lua/5.1/module.lua /usr/local/lib/lua/5.1/module/init.lua
Если целевой файл найден, будет вызвана package.loadfile для загрузки модуля. В противном случае будет выполняться поиск библиотеки программы на C.
Путь поиска файлов берётся из глобальной переменной package.cpath, и эта переменная инициализируется через переменную окружения LUA_CPATH.
Стратегия поиска такая же, как выше, за исключением того, что теперь выполняется поиск файлов типа so или dll. Если файл найден, require загрузит его через package.loadlib.
Пакеты C
Lua и C легко объединять, используя C для написания пакетов для Lua.
В отличие от написания пакетов на Lua, пакеты на C должны быть сначала загружены и подключены, прежде чем их можно использовать. В большинстве систем самый простой способ реализации — через механизм динамически подключаемых библиотек.
Lua предоставляет все функции динамического связывания в функции с именем loadlib. Эта функция имеет два параметра: абсолютный путь к библиотеке и инициализирующую функцию. Итак, типичный пример вызова выглядит следующим образом:
local f = loadlib(path, "luaopen_socket")
Функция loadlib загружает указанную библиотеку и подключает её к Lua. Однако она не открывает библиотеку (то есть не вызывает инициализирующую функцию). Вместо этого она возвращает инициализирующую функцию как функцию Lua, поэтому мы можем вызвать её напрямую из Lua.
Если при загрузке динамической библиотеки или поиске инициализирующей функции возникает ошибка, loadlib вернёт nil и сообщение об ошибке. Мы можем изменить предыдущий код, чтобы обнаружить ошибку, а затем вызвать инициализирующую функцию:
-- Или path = "C:\\windows\\luasocket.dll", это на платформе Windows
local f = assert(loadlib(path, "luaopen_socket"))
f() -- Фактически открываем библиотеку
В общем, мы ожидаем, что бинарная библиотека будет содержать файл-заглушку, похожий на предыдущий фрагмент кода. При установке бинарной библиотеки её можно разместить в любом каталоге, и нужно изменить только фактический путь к бинарной библиотеке, соответствующий файлу-заглушке.
Добавьте каталог, в котором находится файл-заглушка, в LUA_PATH. После этой настройки вы можете использовать функцию require для загрузки библиотеки C.
Другие расширения