English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Модули и пакеты Lua

Модуль ähnelt einer verpackten Bibliothek. С Lua 5.1 Lua получила стандартный механизм управления модулями, который позволяет поместить общие коды в один файл и вызывать их через API в других местах, что способствует повторному использованию кода и снижению зависимости кода.

Модули Lua состоят из таблиц с известными элементами, такими как переменные и функции, поэтому создание модуля очень просто: нужно создать таблицу и добавить в нее необходимые константы и функции, а затем вернуть эту таблицу. Пример создания пользовательского модуля module.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

Таким образом, структура модуля представляет собой структуру table, поэтому можно оперировать с константами или функциями модуля так же, как и с элементами table.

Функция func2 объявлена как локальная переменная блока программы, что означает, что она является частной функцией и не может быть доступна извне, чтобы вызвать эту частную функцию из модуля, необходимо вызвать ее через общедоступные функции модуля.

Функция require

Lua предоставляет функцию require для загрузки модулей. Чтобы загрузить модуль, нужно просто вызвать его. Например:

require("<имя_модуля>")

Или

require "<имя_модуля>"

После выполнения require будет возвращен table, состоящий из констант или функций модуля, и также будет определен глобальная переменная, содержащая этот table.

Файл test_module.lua

-- Файл test_module.lua
-- Модуль module упомянут в module.lua
require("module")
 
print(module.constant)
 
module.func3()

Результат выполнения кода:

Это константа
Это частная функция!

Или определить别名 переменной для загружаемого модуля, чтобы было удобнее вызывать:

Файл test_module2.lua

-- Файл test_module2.lua
-- Модуль module упомянут в module.lua
-- Псевдоним переменной m
local m = require("module")
 
print(m.constant)
 
m.func3()

Результат выполнения кода:

Это константа
Это частная функция!

Механизм загрузки

Для пользовательских модулей, файл модуля не должен быть放在任何一个目录中, функция require имеет свою стратегию загрузки файла пути, она пытается загрузить модуль из файла Lua или библиотеки программы C.

Путь к Lua файлам для поиска, который используется require, хранится в глобальной переменной package.path. После запуска Lua этот путь инициализируется значением переменной окружения LUA_PATH. Если переменная окружения не найдена, используется путь по умолчанию, определенный при компиляции.

Конечно, если переменной окружения LUA_PATH нет, можно также настроить ее вручную. Откройте файл .profile в корневой директории текущего пользователя (если его нет, создайте его, также можно открыть файл .bashrc), например, добавьте путь "~/lua/" в переменную окружения LUA_PATH:

#LUA_PATH
export LUA_PATH="~/lua/?.lua;;"

Пути к файлам разделены символом ";", а последние два ";;" означают, что добавленный путь добавляется к исходному пути по умолчанию.

Затем обновите параметры переменной окружения, чтобы они вступили в силу немедленно.

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") будет versucht открыть следующие каталоги для поиска целевого файла.

/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. Если файл найден, then require использует package.loadlib для его загрузки.

Пакет C

Lua и C легко комбинируются, используя C для написания пакетов.

В отличие от пакетов, написанных на Lua, пакеты на C должны быть сначала загружены и подключены, в большинстве систем наиболее простым способом является использование механизма динамического подключения библиотек.

Lua предоставляет все функции динамического подключения в функции loadlib. Эта функция имеет два параметра: абсолютный путь к библиотеке и инициализационную функцию. Так что пример типичного вызова следующий:

local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")

Функция loadlib загружает указанную библиотеку и подключает её к Lua, но не открывает библиотеку (то есть не вызывает инициализационную функцию), вместо этого она возвращает инициализационную функцию в качестве функции Lua, так что мы можем напрямую вызывать её в Lua.

Если при загрузке динамической библиотеки или поиске инициализационной функции arises ошибка, loadlib возвращает nil и ошибку. Мы можем изменить предыдущий фрагмент кода, чтобы он проверял ошибки и вызывал инициализационную функцию:

local path = "/usr/local/lua/lib/libluasocket.so"
-- или path = "C:\\windows\\luasocket.dll",это Window платформе
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- настоящее открытие библиотеки

В большинстве случаев мы ожидаем, что двоичные библиотеки содержат файл stub, аналогичный предыдущему фрагменту кода, при установке двоичных библиотек вы можете просто положить их в любую папку, достаточно изменить путь к stub файлу для соответствующей двоичной библиотеки.

Добавьте каталог, содержащий файл stub, в LUA_PATH, после этого вы сможете использовать функцию require для загрузки C библиотек.