Lua: специфика языка программирования

Опубликовано:

Данный раздел содержит цикл статей об особенностях языка Lua для тех, кто уже знает основы программирования. Основное назначение — познакомится с синтаксисом и особенностями Lua для последующего более легкого вхождения в область непосредственного использования этого языка, например, в геймдев.

Хотя синтаксис Lua местами напоминает Pascal, по духу он ближе к Python. Поэтому если вы не знакомы с программированием, может быть полезным сначала пройти вводный курс по Python.

Lua задумывался как встраиваемый язык программирования, поэтому его ключевой особенностью является минимализм. Сам по себе интерпретатор (утилита) Lua весит около 300 КБ, так как включает только базовые модули, а не на все случаи жизни, как в том же Python. Встраиваемый язык не нуждается во множестве библиотек. Так в Defold сам движок предоставляет функции для графики и звука, а в Luanti сама игра дает функции для генерации блоков. Поэтому в ядро встраиваемого языка не включают то, что хост-программа все равно заменит своим.

Минимализм языка проистекает не только из ограниченности набора стандартных библиотек, также является следствием отсутствия в нем множества встроенных классов и типов. Вместо этого разработчики Lua реализовали механизмы для создания необходимых сущностей самими прикладными программистами. Хотите ООП, классы и наследование? В Lua их нет, но есть метатаблицы, с помощью которых вы можете собрать любую систему ООП. Хотите массивы, списки, хэш-мапы и множества? В Lua их нет, но есть таблица как тип, которая умеет притворяться всем вышеперечисленным.

Одной из областей использования Lua является геймдев. В то время как движок на C или C++ выполняет компиляцию, Lua-скрипты работают без перекомпиляции. Это дает геймдизайнерам и скриптерам возможность менять логику игры на лету. Можно сказать, что Lua — это язык для облегченного управления системой, написанной на более фундаментальном и сложном языке ("высокоуровневый пульт управления" для сложного низкоуровневого механизма).

Среди прочих особенностями Lua являются:

Lua — это интерпретируемый язык, но его интерпретатор не читает код построчно в процессе работы. Он мгновенно транслирует его в эффективный байт-код для собственной виртуальной машины, что делает запуск практически мгновенным, а "вес" самой среды выполнения — минимальным.

В игровых движках чаще всего используется не стандартный интерпретатор, а LuaJIT (Just-In-Time компилятор), благодаря которому Lua является одним из самых быстрых скриптовых языков в мире. Его производительность в разы выше, чем у стандартного Python или JS. Это важно для игровых циклов (update-функций).

Встраиваемость Lua раскрывается на полную мощность в таких проектах, как Defold и Luanti. Если в Defold язык Lua выступает в роли дирижера, управляющего быстрыми C++ компонентами игры, то в воксельном движке Luanti на Си написан лишь базовый фундамент для рендеринга блоков. Вся игра — от алгоритмов генерации бесконечного мира до физики предметов и логики инвентаря — создается исключительно с помощью Lua API. Это превращает среду в гибкую платформу, где каждый программист может переписать правила открытого мира в обычном текстовом редакторе.

Статьи цикла

  1. Переменные: объявление, экспорт и импорт
    Разбираем переменные в Lua. Уход от глобальных имен, особенности local в функциях и блоках, как правильно настроить экспорт таблиц-модулей через return и require.

  2. Таблицы — основа для сложных типов данных
    Как таблицы заменяют массивы, списки, словари и другие структурированные типы. Краткое руководство по синтаксису и структурам для программистов, переходящих на Lua.

  3. ООП: объекты и классы-таблицы, механизм метатаблиц
    Разбор эмуляции ООП в Lua. Как разделяются роли между таблицами-объектами и таблицами-классами, и как механизм метатаблиц связывает их в единую систему.

  4. Вывод данных в консоль
    Особенности работы функций print и io.write в Lua при выводе данных в консоль. Когда какую использовать, как в Lua форматируется вывод и др.

  5. Итерирование таблиц: циклы, ipairs и pairs
    Обход таблиц в Lua. Обзор циклов, внутреннее устройство for...in, особенности использования ipairs и pairs, пример создания кастомного генератора.

  6. Замыкания: что это, как работают, примеры
    Объясняем замыкания в Lua, их организацию в памяти, индивидуальный и разделяемый контекст. Примеры: генератор итераторов, фабрика функций, инкапсуляция данных.

  7. Безресурсные (stateless) итераторы
    Разбираемся, чем отличаются безресурсные итераторы от на замыканиях. Когда следует их использовать, и как в Lua они завязаны на особенности работы цикла for...in.

  8. Обработка и генерация ошибок
    Изучаем, какие в скриптах Lua могут быть ошибки, как перехватываются с помощью pcall / xpcall. Узнаем, для чего нужен и как работает error, и когда удобнее assert.

  9. Условный оператор и логика в Lua: специфика и реализация
    Обзор синтаксиса if-elseif-else, идиомы and/or как замены тернарного оператора, табличного паттерна для эмуляции оператора выбора, что есть ложь в Lua.

  10. Функции первого класса, высшего порядка и анонимные
    Разбираем, что такое функции первого класса и высшего порядка, и почему для Lua они имеют такое большое значение вместе с анонимными функциями.

  11. Множественный возврат из функций и особенности передачи аргументов
    Обзор специфики множественного возврата значений из функций, передачи произвольного количества аргументов, как передают именованные аргументы в Lua.

  12. Мемоизация: что это и как используется
    Разберем, что такое мемоизация в программировании, и посмотрим на разных примерах, как она реализуется в Lua. Узнаем, в каких случаях и зачем ее используют.

  13. Рандом: math.random, выбор, дроп с весами, перемешивание
    Гайд по случайности в Lua. Примеры кода math.random, случайного выбора, перемешивания (Фишер-Йетс), создания системы лута с весами предметов.

  14. Функции библиотеки table: практические примеры
    Возможности table: добавление и удаление элементов в таблицы, concat, сортировку массивов, упаковку и распаковку, копирование части таблицы в другую.

  15. Работа со строками: основные функции библиотек string и utf8
    На примерах рассматриваем основные функции для работы со строками в Lua, а также особенности языка паттернов Lua. Объясняем назначение модуля utf8.