Lua и Luau — итоги
Кратко — что стоит унести из раздела "Lua и Luau". Если пункт кажется туманным — откройте указанную главу или оглавление.
FAQ — Часто задаваемые вопросы
Типичные сбои и ситуации, с которыми сталкиваются новички после раздела. Здесь — что делать и где копать в главах; определения для зачёта — в чек-листе.
Вопрос. Скрипт из Roblox Studio падает в обычном интерпретаторе Lua с ошибкой про continue или типы.
Ответ. В Studio выполняется Luau (диалект Lua 5.1 с расширениями), а lua в терминале — другая версия и другой набор возможностей. Для переноса кода уберите luau-специфику или запускайте в среде Roblox. Подробнее здесь — Luau, оглавление.
Вопрос. Ошибка "attempt to index a nil value" при обращении к полю таблицы, хотя "ключ точно есть".
Ответ. Чаще всего промежуточное значение nil: obj.field, когда obj не инициализирован, или опечатка в ключе. Проверьте цепочку через print/type, защитите доступ через if obj then. Подробнее здесь — типы и переменные, ООП.
Вопрос. require("mymodule") отвечает "module 'mymodule' not found".
Ответ. Путь ищется по package.path относительно текущего скрипта и LUA_PATH. Файл должен называться mymodule.lua или лежать в подпапке с init.lua. В Roblox require работает по дереву объектов, а не по файловой системе. Подробнее здесь — модули, первая программа.
Вопрос. Перезаписал print или table — весь проект ведёт себя странно.
Ответ. Без local имя попадает в глобальное окружение и затирает стандартную библиотеку. Восстановите из резервной копии или перезапустите интерпретатор; дальше объявляйте всё через local и собирайте API в модульную таблицу. Подробнее здесь — переменные, рекомендации.
Вопрос. ipairs обходит не все элементы массива или останавливается раньше ожидаемого.
Ответ. ipairs идёт по последовательным целым ключам с 1 до первой "дыры". Разреженные таблицы и массивы с индексом 0 обходите через pairs или явный цикл по известным ключам. Подробнее здесь — типы и таблицы, строки и файлы.
Вопрос. Склеивание строк через .. в цикле сильно тормозит или съедает память.
Ответ. Каждый .. создаёт новую строку. Для больших объёмов собирайте части в таблицу и один раз вызывайте table.concat. Подробнее здесь — строки и таблицы, встроенные функции.
Вопрос. Код под LuaJIT падает на Lua 5.4 из‑за goto, битовых операторов или других отличий.
Ответ. LuaJIT зафиксирован на семействе 5.1; 5.4 добавила новый GC, целочисленные правила и синтаксис. Перед деплоем сверяйте целевую VM и тестируйте на той же версии, что в проде. Подробнее здесь — архитектура выполнения, история.
Вопрос. Корoutine создана, но resume ничего не делает или зависает навсегда.
Ответ. Типичные причины — бесконечный цикл без yield, взаимное ожидание двух корутин или забытый второй аргумент resume. Отладка через coroutine.status и явные точки yield. Подробнее здесь — асинхронность и корутины.
Вопрос. pcall поймал ошибку, но программа всё равно записала битые данные в файл.
Ответ. pcall лишь не даёт упасть интерпретатору; логику отката (закрыть файл, не сохранять частичный результат) нужно писать явно в ветке ошибки. Для трассировки используйте xpcall с обработчиком. Подробнее здесь — обработка ошибок.
Вопрос. После настройки метатаблицы программа уходит в бесконечную рекурсию или stack overflow.
Ответ. Часто виноват __index/__newindex, вызывающий себя же при чтении отсутствующего ключа. Разделите "сырой" доступ к таблице (rawget/rawset) и пользовательский API. Подробнее здесь — метатаблицы, ООП.
Вопрос. Метод объекта работает через :, но ломается при вызове через . с тем же именем.
Ответ. Синтаксис obj:method() передаёт obj первым аргументом (self); obj.method() — нет. При передаче функции как колбэка сохраняйте связку через function() obj:method() end. Подробнее здесь — ООП, функции.
Вопрос. Lua-скрипт в Redis обрывается по timeout, хотя "логика простая".
Ответ. Скрипт выполняется атомарно и на одном ядре; длинные циклы и тяжёлая логика блокируют сервер. Перенесите агрегацию в клиент или разбейте операции; не обращайтесь к сети из EVAL. Подробнее здесь — экосистема, архитектура.
Вопрос. OpenResty/nginx "залипает" под нагрузкой после добавления Lua в access_by_lua.
Ответ. В фазах nginx нельзя делать блокирующий I/O и долгие вычисления — worker перестаёт обслуживать соединения. Выносите тяжёлую работу во внешний сервис или используйте cosocket с неблокирующим API. Подробнее здесь — экосистема, архитектура.
Вопрос. Конфиг Neovim на Lua падает: "attempt to call field 'fn' (a nil value)".
Ответ. Частая путаница между vim.api и require('plenary'), устаревшим API или модулем, не загруженным до вызова. Проверьте :checkhealth, версию Neovim и порядок require в init.lua. Подробнее здесь — экосистема, модули.
Вопрос. При встраивании Lua в C приложение падает с "stack overflow" или "bad argument".
Ответ. C API требует сбалансировать стек: каждый lua_push* должен иметь парный pop/return, индексы проверяйте после lua_pcall. Неверный тип аргумента на стеке — частая причина "bad argument #N". Подробнее здесь — архитектура и встраиваемость.
Вопрос. В Luau анализатор типов ругается на код, который "всегда работал" в динамическом Lua.
Ответ. Статическая проверка ловит ветки, где тип не сужается (union, optional). Добавьте аннотации, assert(typeof(x) == "number") или явные guard-условия; --!nocheck оставьте только на границах с внешним API. Подробнее здесь — Luau.
Вопрос. Оператор # для таблицы возвращает не то количество элементов, которое вижу в данных.
Ответ. Длина массива в Lua — граница последовательности от 1 без дыр; # на смешанной таблице может удивить. Для словарей считайте элементы вручную или храните размер отдельно. Подробнее здесь — типы и таблицы.
Вопрос. tonumber("3,14") даёт nil — пользовательский ввод "ломает" расчёт.
Ответ. tonumber ожидает точку как разделитель (или явную base). Нормализуйте локаль (gsub(",", ".")) и проверяйте результат перед арифметикой. Подробнее здесь — типы, строки.
Вопрос. Функция возвращает два значения, а в переменной оказалось только первое — второе "пропало".
Ответ. Присваивание одной переменной берёт только первый результат; лишние отбрасываются. Для всех значений пишите local a, b = f() или оборачивайте в таблицу. Подробнее здесь — функции.
Вопрос. В цикле все замыкания возвращают одно и то же значение счётчика (классическая ловушка).
Ответ. Замыкание захватывает переменную, а не моментальный снимок. Создайте локальную копию на каждой итерации: local i = i внутри тела или используйте параметр IIFE. Подробнее здесь — функции и замыкания.
Вопрос. В игре периодические фризы совпадают с работой сборщика мусора.
Ответ. Tracing GC делает stop-the-world паузы, особенно при большом числе короткоживущих таблиц. Уменьшайте аллокации в hot path, переиспользуйте таблицы, при необходимости настраивайте collectgarbage("setpause") / generational mode в 5.4. Подробнее здесь — память и GC.
Вопрос. Нужно выполнять пользовательские скрипты в моде — как не дать им вызвать os.execute?
Ответ. Запускайте код в песочнице: отдельное окружение без io/os/debug, whitelist через setfenv/load с кастомным _ENV. Никогда не loadstring чужой код без изоляции. Подробнее здесь — обработка ошибок, архитектура.
Вопрос. Шаблоны Lua (string.match с %d) не работают как "регулярки" из Python или JS.
Ответ. В Lua — собственный класс паттернов (%a, %d, захват в скобках), не PCRE. Для сложного разбора подключайте LPeg или lrex; простые задачи решайте через gmatch/gsub. Подробнее здесь — строки, справочник.
Вопрос. if user and user.admin then не срабатывает, хотя admin = false — доступ открыт.
Ответ. В Lua только nil и false ложны; 0 и "" — истинны. Для флагов явно сравнивайте с true или используйте строгую схему полей. Подробнее здесь — типы и логика, основы.
Вопрос. Локальная функция "используется до объявления" — ошибка на строке выше local function f.
Ответ. local function f() — это присваивание после объявления имени; взаимная рекурсия требует local f; function f() ... end. Переставьте определения или разделите forward declaration. Подробнее здесь — функции, синтаксис.
Вопрос. Хочу писать под WoW/Redis/игру — с чего начать, если знаю только Python?
Ответ. Сначала таблицы, модули и local на чистом Lua, затем читайте ограничения конкретной платформы (API хоста, sandbox). Универсальный маршрут — первая программа → основы → приложения. Подробнее здесь — оглавление.
Вопрос. LuaRocks установил пакет, но require всё равно его не видит.
Ответ. Проверьте, что luarocks path добавлен в LUA_PATH/LUA_CPATH для той же версии Lua, которой вы запускаете скрипт. На Windows часто путают несколько установок lua.exe. Подробнее здесь — экосистема, модули.
Вопрос. Чем Luau отличается от Lua и что использовать в Roblox?
Ответ. Luau — диалект на базе Lua 5.1 с типами, continue и оптимизациями под Roblox Studio; классический Lua (5.4) — для Redis, Neovim, встраивания в C. В Roblox пишите Luau. Подробнее здесь — Luau, оглавление.
Вопрос. Как научиться Lua с нуля для Roblox / игровых скриптов?
Ответ. Старт: установить Roblox Studio, пройти таблицы, функции, события на Luau, затем API платформы. База языка — в первой программе и основах. Подробнее здесь — Luau.
Вопрос. Lua или Python — что лучше для модов и скриптов в играх?
Ответ. Lua чаще встроен в движки (Roblox, WoW, многие AAA) как лёгкий скриптовый слой; Python — для инструментов и серверов с богатой экосистемой. Выбор определяет хост, а не "универсальная лучшая". Подробнее здесь — экосистема, архитектура.
Вопрос. Как встроить Lua в программу на C или C++?
Ответ. Подключают liblua, создают lua_State, регистрируют C-функции через lua_register / luaL_newlib, вызывают скрипт через luaL_dofile. Граница хост ↔ скрипт проектируется заранее. Подробнее здесь — архитектура и встраиваемость.
Вопрос. Lua-скрипты в Redis — зачем и как написать простой EVAL?
Ответ. Скрипт выполняется атомарно на сервере — удобно для условных обновлений ключей без гонок. Пишут короткую логику на Lua 5.1, передают ключи и аргументы в EVAL. Подробнее здесь — экосистема, справочник.
Вопрос. Что такое LuaJIT и когда он нужен вместо обычного Lua?
Ответ. LuaJIT — реализация Lua 5.1 с JIT: сильно ускоряет hot loops (игры, OpenResty, embedded). Несовместим с синтаксисом 5.4; проверяйте целевую VM перед деплоем. Подробнее здесь — архитектура, история.
Вопрос. Как настроить Neovim на Lua (init.lua) с нуля?
Ответ. Создайте init.lua в config path, подключайте модули через require, плагины — lazy.nvim или аналог. API — vim.* и :help lua-guide. Подробнее здесь — экосистема, модули.
Вопрос. OpenResty / nginx lua — как начать писать access_by_lua?
Ответ. OpenResty — nginx + LuaJIT; логику вешают на фазы (access, content, log). Изучите ngx.* API и ограничение: без блокирующего I/O в worker. Подробнее здесь — экосистема, архитектура.
Вопрос. Как установить Lua на Windows 10 / Windows 11?
Ответ. Скачайте сборку с lua.org, через Chocolatey/scoop или LuaRocks installer; проверьте lua -v в PATH. Для Roblox отдельная установка не нужна — Studio уже содержит Luau. Подробнее здесь — первая программа.
Вопрос. Lua 5.4 и Lua 5.1 — в чём главные отличия?
Ответ. В 5.4 — generational GC, целочисленный режим, <const>; Luau и LuaJIT опираются на 5.1. Перед переносом скрипта сверьте версию хоста. Подробнее здесь — история, Luau.
Вопрос. Как сделать класс и наследование в Lua без встроенного ООП?
Ответ. Через таблицы + метатаблицы: объект — table, методы в __index, наследование — цепочка metatable. Оператор : передаёт self. Подробнее здесь — ООП, метатаблицы.
Вопрос. Таблица Lua как массив — с чего начинается индекс, 0 или 1?
Ответ. Последовательный массив принято с индекса 1; #t и ipairs рассчитаны на это. Индекс 0 возможен, но ломает идиомы. Подробнее здесь — типы и таблицы.
Вопрос. Как запустить lua-файл из командной строки?
Ответ. Команда lua script.lua или lua -e 'print("hi")'. Интерактив — lua без аргументов. Shebang #!/usr/bin/env lua на Unix. Подробнее здесь — первая программа.
Вопрос. World of Warcraft addons на Lua — с чего начать изучение API?
Ответ. WoW использует Lua 5.1 + WoW API (фреймы, события, secure templates). Сначала таблицы и события Lua, затем документация Blizzard/UI. Подробнее здесь — основы, экосистема.
Вопрос. Как читать и писать файл в Lua?
Ответ. Через io.open, :read, :write, :close; для больших файлов — построчно. В sandbox (игры, Redis) io может быть отключён. Подробнее здесь — строки и файлы.
Вопрос. loadstring и dofile — безопасно ли выполнять код из строки?
Ответ. Выполнение произвольного текста — риск RCE, если нет песочницы. Используйте load с кастомным _ENV, whitelist API; чужой код не запускайте. Подробнее здесь — обработка ошибок, архитектура.
Вопрос. EmmyLua / VS Code — как настроить подсветку и типы для Lua?
Ответ. Плагин EmmyLua или sumneko/lua в VS Code/Cursor; для Luau — отдельные stubs Roblox. Аннотации ---@param улучшают автодополнение. Подробнее здесь — Luau, рекомендации.
Вопрос. Сколько весит интерпретатор Lua и подходит ли он для микроконтроллеров?
Ответ. Ядро Lua — десятки–сотни КБ в embedded-сборке; один из причин выбора для роутеров и IoT. Нужен порт под платформу и ограничение API. Подробнее здесь — архитектура, экосистема.
Вопрос. Как сделать бесконечный цикл while true в Lua для игрового tick?
Ответ. while true do ... end с wait() или yield в движке; без паузы зависнет поток. В Roblox — task.wait(), в чистом Lua — корутины или события хоста. Подробнее здесь — циклы, корутины.
Вопрос. Lua table sort — как отсортировать массив таблиц по полю?
Ответ. table.sort(t, function(a,b) return a.score > b.score end) — компаратор как в C. Сортировка in-place; для immutable-подхода копируйте таблицу. Подробнее здесь — строки и таблицы, встроенные функции.
Вопрос. Где Lua используется в реальных проектах кроме игр?
Ответ. Redis, Nginx/OpenResty, Neovim, Wireshark, HAProxy, встраивание в промышленное ПО и конфигурацию. Список кейсов — в экосистеме.
Вопрос. Как передать несколько значений из функции Lua?
Ответ. return a, b, c — вызывающий получает несколько результатов; local x = f() сохранит только первый. Для упаковки используйте table. Подробнее здесь — функции.
Вопрос. Luau type annotation example — как указать тип переменной в Roblox?
Ответ. Синтаксис: local n: number = 0, function f(x: string): boolean. Анализатор Studio подскажет несовместимость до запуска. Подробнее здесь — Luau.
Вопрос. Sol2 / LuaBridge — что выбрать для связки Lua и C++?
Ответ. Обе оборачивают C API: Sol2 — header-only, современный C++; LuaBridge — легче, меньше магии. Выбор по стилю проекта и версии Lua. Подробнее здесь — архитектура, экосистема.
Что запомнить
Lua — это лёгкий, интерпретируемый, динамически типизированный язык программирования, разработанный в Бразилии в начале 1990-х годов. Он создан для встраивания в приложения на C/C++ и отличается минимальным размером, высокой производительностью и гибкостью. Lua не претендует на роль универсального языка, но идеально подходит как скриптовый движок для игр, сетевых приложений, конфигурации и расширения функциональности.
Основные особенности Lua:
- Минимализм: ядро языка содержит всего 20–30 ключевых понятий;
- Единая структура данных — таблица (
table) — используется как массив, словарь, объект, модуль, пространство имён; - Функции первого класса — функции можно присваивать переменным, передавать как аргументы, возвращать из других функций;
- Лексические замыкания: мощный инструмент для создания абстракций и инкапсуляции;
- Сборка мусора: tracing GC (инкрементальный, в Lua 5.4 — с generational mode);
- Отсутствие встроенных классов: ООП реализуется через метатаблицы и прототипы;
- Простая C API: позволяет легко интегрировать Lua в хост-приложение.
Области применения Lua:
- Игровая индустрия — World of Warcraft, Roblox, Angry Birds, Civilization;
- Серверы и данные: Redis (Lua-скрипты), Nginx/OpenResty;
- Встраиваемые системы — маршрутизаторы, IoT-устройства, промышленное ПО;
- Конфигурация и автоматизация — Neovim, HAProxy, Nginx (OpenResty), Wireshark;
- Прототипирование и DSL: благодаря гибкому синтаксису и метапрограммированию.
Luau — диалект на базе Lua 5.1, разработанный Roblox. Он добавляет:
- Статическую типизацию (опциональную, с аннотациями типов);
- Улучшенную производительность за счёт оптимизированного компилятора и рантайма;
- Поддержку современных конструкций —
continue, улучшенные циклы, безопасные вызовы; - Интеграцию с IDE — автодополнение, навигация, рефакторинг в Roblox Studio.
Экосистема Lua включает:
- LuaRocks — менеджер пакетов;
- luajit — высокопроизводительная реализация с JIT-компиляцией;
- tolua++, Sol2, LuaBridge — библиотеки для связки с C++;
- ZeroBrane Studio, VS Code + EmmyLua — инструменты разработки.
Три основных правила эффективной работы с Lua:
- Использовать таблицы как универсальный строительный блок — для структур, модулей, объектов;
- Избегать глобальных переменных — всё помещать в локальные или модульные таблицы;
- Проектировать API так, чтобы хост-приложение и скрипты взаимодействовали через чёткие границы.
Три фундаментальных момента:
- Lua — это "язык для встраивания";
- Его сила — в простоте и согласованности: одна таблица решает множество задач;
- Luau расширяет Lua, делая его пригодным для крупных проектов за счёт типизации и инструментов.
Куда идти дальше
| Тема | Раздел |
|---|---|
| "Swift — о разделе" | "Swift — о разделе" |
| "Cobol — о разделе" | "Cobol — о разделе" |
| "Rust — о разделе" | "Rust — о разделе" |
| "Fortran — о разделе" | "Fortran — о разделе" |
Проверьте себя: Чек-лист самопроверки.