Lua — легкий встраиваемый скриптовый язык программирования: маленькое ядро на C, простой синтаксис и одна универсальная структура данных — таблица. Его редко берут как единственный язык проекта; чаще Lua встраивают внутрь программы на C или C++, чтобы описывать на нем логику, конфигурацию и сценарии. Ниже разберем, как устроен синтаксис, почему таблица заменяет и массив, и словарь, что означает «компилятор» применительно к Lua, и где язык реально работает — от игр до nginx и Redis.
Содержание
- Интерпретируемый язык, байткод и luac: что здесь «компилятор»
- Первая рабочая программа
- Синтаксис: переменные и типы данных
- Множественное присваивание и функции
- Таблица — единственная структура данных
- Метатаблицы: коротко о механизме поведения
- Типичная ошибка новичка
- Где применяется Lua
- Немного истории
- Выводы
- Где применяется / связь с практикой
- FAQ
Актуальная стабильная ветка на сентябрь 2026 — Lua 5.4 (внутри выходят точечные обновления 5.4.x с исправлениями). Все примеры ниже рассчитаны на нее.
Интерпретируемый язык, байткод и luac: что здесь «компилятор»
Слово «компилятор» в старом названии статьи вводит в заблуждение, поэтому разведем термины сразу.
- Компилируемый язык (например, C) целиком переводится в машинный код процессора отдельной программой-компилятором, и уже готовый бинарник запускает операционная система.
- Интерпретируемый язык исполняется программой-интерпретатором, а не напрямую процессором.
Lua относится ко второму типу, но с нюансом. Интерпретатор не читает исходный текст построчно каждый раз: при загрузке он сначала транслирует код в байткод (компактные инструкции), а затем этот байткод исполняет виртуальная машина Lua — программный «процессор» со своими регистрами. То есть внутренняя компиляция в байткод есть, а компиляции в машинный код платформы — нет.
Отдельно поставляется утилита luac — это прекомпилятор: он заранее превращает .lua-файл в файл байткода, но снова не в машинный код. Запускать такой файл все равно будет виртуальная машина Lua.
# прекомпиляция исходника в байткод (не в машинный код платформы)
luac -o hello.luac hello.lua
# запуск байткода тем же интерпретатором
lua hello.luac
Вывод в консоли будет таким же, как при запуске lua hello.lua. Важно: файл hello.luac не самостоятельный исполняемый файл, для него по-прежнему нужен интерпретатор lua.
Первая рабочая программа
Начнем с минимального полного примера, который можно сохранить в файл hello.lua и запустить командой lua hello.lua.
-- hello.lua
local name = "Otus"
local version = _VERSION -- глобальная строка вида "Lua 5.4"
print("Привет, " .. name)
print("Версия: " .. version)
Вывод в консоль:
Привет, Otus
Версия: Lua 5.4
Разберем по строкам. Комментарий начинается с --. Ключевое слово local объявляет локальную переменную (без него имя стало бы глобальным — в Lua это разрешено, но локальные переменные предпочтительнее). Оператор .. склеивает строки. Функция print печатает аргументы и добавляет перевод строки; несколько аргументов она разделяет табуляцией.
Синтаксис: переменные и типы данных
Lua — язык с динамической типизацией: тип принадлежит значению, а не переменной, поэтому одна и та же переменная может по очереди хранить число, строку или таблицу. Объявлять тип заранее не нужно.
В Lua 5.4 восемь базовых типов: nil, boolean, number, string, function, table, thread (сопрограммы) и userdata (данные из внешнего кода на C). Коротко о ключевых:
nil— отсутствие значения; переменная без присвоенного значения равнаnil.boolean—trueилиfalse. Отдельно запомните: в условиях «ложными» считаются толькоfalseиnil, а число0и пустая строка — истинны.number— числа. Начиная с Lua 5.3 у типа два подвида: целые (integer) и с плавающей точкой (float).string— строки, неизменяемые (любая операция создает новую строку).
print(math.type(10)) -- integer
print(math.type(10.0)) -- float
print(7 // 2) -- 3 целочисленное деление
print(7 / 2) -- 3.5 обычное деление всегда дает float
Вывод:
integer
float
3
3.5
Функция math.type показывает подвид числа, а // — это целочисленное деление (округление вниз), тогда как / всегда возвращает float.
Множественное присваивание и функции
Lua умеет присваивать несколько значений за одну строку, поэтому обмен двух переменных пишется без временной переменной:
local a, b = 1, 2
a, b = b, a
print(a, b) -- 2 1
Число переменных и значений слева и справа не обязано совпадать: лишние значения отбрасываются, недостающим присваивается nil. Функции — полноправные значения (их можно передавать в аргументы и возвращать), и они тоже умеют возвращать несколько результатов:
local function minmax(x, y)
if x < y then
return x, y
end
return y, x
end
local lo, hi = minmax(9, 4)
print(lo, hi) -- 4 9
Функция minmax возвращает пару значений, которую мы сразу раскладываем в две переменные lo и hi.
Таблица — единственная структура данных
Ключевая особенность Lua: массив, словарь, список, множество, объект и даже пространство имен — все это одна и та же структура, таблица. Таблица — это ассоциативный массив пар «ключ-значение», где ключом может быть почти любое значение, кроме nil.
Как массив таблица индексируется с единицы (не с нуля, как во многих языках — это частый источник ошибок при переходе):
local t = {} -- пустая таблица
t[1] = "a" -- используем как массив
t[2] = "b"
t.color = "red" -- та же таблица как словарь: t["color"]
print(#t) -- 2 длина массивной части
print(t.color) -- red
Вывод:
2
red
Оператор # дает длину массивной (целочисленной) части таблицы; ключ color в нее не входит. Запись t.color — это сокращение для t["color"].
Для перебора есть два способа: ipairs идет по целочисленным индексам подряд от 1, pairs обходит все ключи (порядок для нечисловых ключей не гарантируется).
local fruits = {"apple", "banana", "cherry"}
for i, v in ipairs(fruits) do
print(i, v)
end
Вывод:
1 apple
2 banana
3 cherry
Литерал {"apple", "banana", "cherry"} — это та же таблица, где ключи 1, 2, 3 проставлены автоматически.
Метатаблицы: коротко о механизме поведения
Метатаблица — это обычная таблица, которую привязывают к другой таблице, чтобы задать ее поведение в особых ситуациях: сложение, сравнение, обращение к отсутствующему ключу. Специальные поля метатаблицы называются метаметодами (их имена начинаются с двух подчеркиваний). На метатаблицах в Lua строят объектную модель, потому что отдельного синтаксиса классов в языке нет.
Ниже минимальный пример: сделаем тип «вектор» и научим оператор + складывать два вектора через метаметод __add.
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({x = x, y = y}, Vector)
end
function Vector.__add(a, b)
return Vector.new(a.x + b.x, a.y + b.y)
end
local v = Vector.new(1, 2) + Vector.new(3, 4)
print(v.x, v.y) -- 4 6
Вывод:
4 6
Функция setmetatable привязывает метатаблицу Vector к новому объекту. Когда интерпретатор встречает + между двумя такими объектами, он вызывает метаметод __add. Это упрощенная модель объектов: полноценные наследование и приватность делаются теми же метатаблицами, но подробности выходят за рамки знакомства с языком.
Типичная ошибка новичка
Обращение к полю значения, которого нет, дает ошибку выполнения, а не «тихий» nil:
local user = {name = "Ana"}
print(user.age.years)
Результат (текст и префикс зависят от способа запуска):
lua: hello.lua:2: attempt to index a nil value (field 'age')
Поля age в таблице нет, значит user.age равно nil, а обращение к .years у nil недопустимо. Правильно — сначала проверить наличие значения:
local user = {name = "Ana"}
print(user.age) -- nil, это не ошибка
print(user.age and user.age.years) -- nil, безопасное обращение
Идиома a and a.b возвращает nil, если a равно nil, и не роняет программу.
Где применяется Lua
Сильная сторона Lua — встраивание: интерпретатор занимает сотни килобайт и легко подключается к программе на C или C++, отдавая сценаристам и пользователям безопасный способ менять логику без пересборки основного приложения. Отсюда и типичные ниши.
| Область | Как используется | Примеры |
|---|---|---|
| Игры | Скрипты игровой логики поверх движка на C++ | Движок LOVE (LOVE2D), аддоны World of Warcraft |
| Игровые платформы | Встроенный язык сценариев для пользователей | Roblox (диалект Luau на основе Lua) |
| Веб и прокси | Обработка запросов внутри веб-сервера | nginx через OpenResty (на LuaJIT) |
| Базы данных | Серверные скрипты на стороне хранилища | Redis (команда EVAL исполняет Lua) |
| Приложения | Конфигурация и расширения (плагины) | Встраивание в утилиты на C/C++ |
Два уточнения, чтобы не путать близкие вещи. Roblox использует не «чистый» Lua, а собственный диалект Luau (типизированное расширение на базе Lua 5.1). OpenResty работает не на эталонной виртуальной машине, а на LuaJIT — отдельной реализации с JIT-компиляцией, совместимой с Lua 5.1. Это разные реализации одной идеи языка, и версия там может отличаться от эталонной 5.4.
Немного истории
Lua создан в 1993 году в Католическом университете Рио-де-Жанейро (PUC-Rio); авторы — Роберто Иерусалимски, Вальдемар Селес и Луис Энрике ди Фигейреду. Предшественниками были внутренние языки SOL и DEL. Название Lua по-португальски означает «луна». С самого начала язык распространяется с открытым исходным кодом и написан на переносимом ANSI C — отсюда его портируемость между операционными системами.
Выводы
- Lua — легкий встраиваемый скриптовый язык; чаще всего он живет внутри программы на C или C++, а не как самостоятельный проект.
- Lua интерпретируемый: исходник компилируется во внутренний байткод и исполняется виртуальной машиной Lua;
luacлишь заранее готовит байткод, но не машинный код платформы. - Таблица — единственная структура данных, которая играет роль и массива (индексы с 1), и словаря, и основы объектов.
- Метатаблицы задают поведение таблиц (операторы, доступ к полям) и заменяют отдельный синтаксис классов.
- Основные ниши: игры, встраивание в приложения, nginx/OpenResty и Redis; реализации бывают разные (эталонная ВМ, LuaJIT, Luau).
Где применяется / связь с практикой
Lua редко изучают в вакууме: его ценность раскрывается там, где скриптовый слой встроен в системную программу на C или C++ — игровой движок, сетевой прокси, хранилище данных. Чтобы уверенно связывать такой слой с ядром приложения, нужно понимать управление памятью, сборку и вызовы C API — это уже область системного программирования.
Освойте тему на практике
Разобраться с тем, как встраиваемые языки стыкуются с кодом на C/C++, помогает курс Программист C/C++: системная разработка. Если хочется сначала посмотреть формат и уровень без обязательств, загляните на открытые уроки Otus — там разбирают практические темы вживую.
FAQ
Lua и Luau — это одно и то же?
Нет. Lua — эталонный язык (актуальная ветка 5.4), а Luau — его отдельный диалект от Roblox с необязательной статической типизацией, построенный на базе Lua 5.1. Код на «чистом» Lua 5.4 не гарантированно запустится в Luau и наоборот.
Можно ли собрать из Lua-скрипта самостоятельный exe-файл?
Утилита luac дает файл байткода, но для его запуска все равно нужен интерпретатор. Отдельный исполняемый файл получают сторонними упаковщиками, которые кладут интерпретатор и скрипт в один бинарник; это не входит в стандартную поставку языка.
Почему индексация массивов начинается с 1, а не с 0?
Это решение авторов языка: в Lua целочисленные ключи таблиц по соглашению идут с 1, и на это рассчитаны ipairs, оператор # и стандартные библиотеки. Технически ключом может быть и 0, но тогда стандартные механизмы длины и перебора будут работать не так, как ожидается.



