Lua – скрипты Lua. Язык программирования Lua

Lua предлагает высокоуровневую абстракцию без потери связи с аппаратурой

В то время как интерпретируемые языки программирования, такие как Perl, Python, PHP и Ruby, пользуются все большей популярностью для Web-приложений (и уже давно предпочитаются для автоматизации задач по системному администрированию), компилируемые языки программирования, такие как C и C++, по-прежнему необходимы. Производительность компилируемых языков программирования остается несравнимой (она уступает только производительности ручного ассемблирования), поэтому некоторое программное обеспечение (включая операционные системы и драйверы устройств) может быть реализована эффективно только при использовании компилируемого кода. Действительно, всегда, когда программное и аппаратное обеспечение нужно плавно связать между собой, программисты инстинктивно приходят к компилятору C: C достаточно примитивен для доступа к "голому железу" (то есть, для использования особенностей какой-либо части аппаратного обеспечения) и, в то же время, достаточно выразителен для описания некоторых высокоуровневых программных конструкций, таких как структуры, циклы, именованные переменные и области видимости.

Однако языки сценариев тоже имеют четкие преимущества. Например, после успешного переноса интерпретатора языка на другую платформу подавляющее большинство написанных на этом языке сценариев работает на новой платформе без изменений, не имея зависимостей, таких как системные библиотеки функций (представьте множество DLL-файлов операционной системы Microsoft® Windows® или множество libcs на UNIX® и Linux®). Кроме того, языки сценариев обычно предлагают высокоуровневые программные конструкции и удобные операции, которые программистам нужны для повышения продуктивности и скорости разработки. Более того, программисты, использующие язык сценариев, могут работать быстрее, поскольку этапы компиляции и компоновки не нужны. В сравнении с С и его родственниками цикл "кодирование, компоновки, связывание, запуск" сокращается до ускоренного "написание, запуск".

Новшества в Lua

Как и любой язык сценариев, Lua имеет свои особенности:

  • Типы в Lua . В Lua значения имеют тип, но переменные типизируются динамически. Типы nil , boolean , number и string работают так, как вы могли бы ожидать.
    • Nil - это тип специального значения nil ; используется для представления отсутствия значения.
    • Boolean - это тип констант true и false (Nil тоже представляет значение false , а любое не nil значение представляет true).
    • Все числа в Lua имеют тип doubles (но вы можете легко создать код для реализации других числовых типов).
    • string - это неизменяемый массив для символов (следовательно, для добавления к строке вы должны сделать ее копию).
  • Типы table , function и thread являются ссылками. Каждый такой тип может быть назначен переменной, передаваемой в качестве аргумента, или возвращаемой из функции. Ниже приведен пример сохранения функции:

    Пример анонимной функции, -- возвращаемой как значение -- см. http://www.tecgraf.puc-rio.br/~lhf/ftp/doc/hopl.pdf function add(x) return function (y) return (x + y) end end f = add(2) print(type(f), f(10)) function 12

  • Потоки в Lua . Поток - это сопрограмма, создаваемая вызовом встроенной функции coroutine.create(f) , где f - это функция Lua. Потоки не запускаются при создании; они запускаются позже при помощи функции coroutine.resume(t) , где t - это поток. Каждая сопрограмма может время от времени отдавать процессор другим сопрограммам при помощи функции coroutine.yield() .
  • Выражения присваивания . Lua разрешает множественные присваивания, и выражения сначала вычисляются, а затем присваиваются. Например, результат выражений

    I = 3 a = {1, 3, 5, 7, 9} i, a[i], a, b = i+1, a, a[i] print (i, a, a, b, I)
    равен 4 7 5 nil nil . Если список переменных больше, чем список значений, лишним переменным присваивается значение nil ; поэтому b равно nil . Если значений больше, чем переменных, лишние значения просто игнорируются. В Lua названия переменных зависят от регистра символов, что объясняет, почему переменная I равна nil .

  • Порции (chunks) . Порцией называется любая последовательность Lua-операторов. Порция может быть записана в файл или в строку в Lua-программе. Каждая порция выполняется как тело анонимной функции. Следовательно, порция может определять локальные переменные и возвращать значения.
  • Дополнительные интересные возможности . Lua имеет сборщик мусора "отметь и выкинь". В Lua 5.1 сборщик мусора работает в инкрементном режиме. Lua имеет полное лексическое замыкание (как Scheme, но не как Python). Кроме того, Lua имеет надежную семантику последовательных вызовов (tail call) (опять же, как Scheme, но не как Python).

Большее количество примеров Lua-кода приведено в руководстве "Программирование в Lua " и в wiki Lua-пользователей (ссылки приведены в разделе " ").

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

Беря все лучшее из обоих миров

Что, если бы вы могли взять лучшее из обоих миров: производительность работы с "голым железом" и высокоуровневые, мощные абстракции? Более того, если бы вы могли оптимизировать алгоритмы и функции, зависящие от системы и требующие много процессорного времени, так же как и отдельную логику, не зависящую от системы и очень чувствительную к изменениям требований?

Баланс требований для высокопроизводительного кода и высокоуровневого программирования является сутью Lua, встраиваемого языка программирования. Приложения, включающие Lua, представляют собой комбинацию компилируемого кода и Lua-сценариев. Компилируемый код может при необходимости заняться железом, и, в то же время, может вызывать Lua-сценарии для обработки сложных данных. И поскольку Lua-сценарии отделены от компилируемого кода, вы можете изменять сценарии независимо от него. С Lua цикл разработки более похож на "Кодирование, компоновка, запуск, создание сценариев, создание сценариев, создание сценариев …".

Например, на странице "Uses" Web-сайта Lua (см. раздел " ") перечислены некоторые компьютерные игры для массового рынка, включая World of Warcraft и Defender (версия классической аркады для бытовых консолей), которые интегрируют Lua для запуска всего, начиная с пользовательского интерфейса и заканчивая искусственным интеллектом противника. Другие приложения Lua включают в себя механизмы расширения для популярного инструментального средства обновления Linux-приложений apt-rpm и механизмы управления чемпионатом Robocup 2000 "Сумасшедший Иван". На этой странице есть много хвалебных отзывов о маленьком размере и отличной производительности Lua.

Начало работы с Lua

Lua версии 5.0.2 на момент написания данной статьи была текущей версией (недавно появилась версия 5.1). Вы можете загрузить исходный код Lua с lua.org, а можете найти различные предварительно откомпилированные двоичные файлы на wiki Lua-пользователей (ссылки приведены в разделе " "). Полный код ядра Lua 5.0.2, включая стандартные библиотеки и Lua-компилятор, по размерам не превышает 200KB.

Если вы работаете на Debian Linux, то можете быстро и просто установить Lua 5.0 при помощи следующей команды

# apt-get install lua50

с правами суперпользователя. Все приведенные здесь примеры запускались на Debian Linux "Sarge" с использованием Lua 5.0.2 и ядра Linux 2.4.27-2-686.

После установки Lua на вашей системе попробуйте автономный Lua-интерпретатор. Все Lua-приложения должны быть встроены в базовое приложение. Интерпретатор - это просто специальный тип базового приложения, используемого для разработки и отладки. Создайте файл factorial.lua и введите в него следующие строки:

-- определяет функцию факториала function fact (n) if n == 0 then return 1 else return n * fact(n-1) end end print("enter a number:") a = io.read("*number") print(fact(a))

Код в factorial.lua (точнее, любая последовательность Lua-операторов) называется порцией (chunk), как было описано выше в разделе " ". Для запуска созданной вами порции выполните команду lua factorial.lua:

$ lua factorial.lua enter a number: 10 3628800

Или, как в других языках сценариев, вы можете добавить строку со знаками (#!) ("shebang") в начало сценария, делая сценарий исполняемым, а затем запустить файл как автономную команду:

$ (echo "#! /usr/bin/lua"; cat factorial.lua) > factorial $ chmod u+x factorial $ ./factorial enter a number: 4 24

Язык Lua

Lua обладает многими удобствами, имеющимися в современных языках программирования сценариев: область видимости, управляющие структуры, итераторы и стандартные библиотеки для обработки строк, выдачи и сбора данных и выполнения математических операций. Полное описание языка Lua приведено в "" (см. раздел " ").

В Lua тип имеют только значения , а переменные типизируются динамически. В Lua есть восемь фундаментальных типов (или значений): nil , boolean , number , string , function , thread , table и userdata . Первые шесть типов говорят сами за себя (исключения приведены в разделе " "); два последних требуют пояснения.

Таблицы в Lua

Таблицы - это универсальная структура данных в Lua. Более того, таблицы - это единственная структура данных в Lua. Вы можете использовать таблицу как массив, словарь (называемый также хеш-таблицей или ассоциативным массивом ), дерево, запись и т.д.

В отличие от других языков программирования, содержимое таблицы в Lua не обязательно должно быть однородным: таблица может включать любые типы и может содержать смесь элементов, подобных массиву, и элементов, подобных словарю. Кроме того, любое Lua-значение (в том числе, функция или другая таблица) может служить ключом элемента словаря.

Для исследования таблиц запустите Lua-интерпретатор и введите строки, показанные жирным шрифтом в листинге 1.

Листинг 1. Экспериментируя с таблицами Lua
$ lua > -- создать пустую таблицу и добавить несколько элементов > t1 = {} > t1 = "moustache" > t1 = 3 > t1["brothers"] = true > -- создать таблицу и определить элементы (употребляется чаще) > all at once > t2 = { = "groucho", = "chico", = "harpo"} > t3 = { = t2, accent = t2, horn = t2} > t4 = {} > t4 = "the marx brothers" > t5 = {characters = t2, marks = t3} > t6 = {["a night at the opera"] = "classic"} > -- создать ссылку и строку > i = t3 > s = "a night at the opera" > -- индексами могут быть любые Lua-значения > print(t1, t4, t6[s]) moustache the marx brothers classic > -- фраза table.string эквивалентна фразе table["string"] > print(t3.horn, t3["horn"]) harpo harpo > -- индексы могут быть также "многомерными" > print (t5["marks"]["horn"], t5.marks.horn) harpo harpo > -- i указывает на то же значение, что и t3 > = t4[i] the marx brothers > -- несуществующие индексы возвращают значения nil > print(t1, t2, t5.films) nil nil nil > -- даже функция может быть ключом > t = {} > function t.add(i,j) >> return(i+j) >> end > print(t.add(1,2)) 3 > print(t["add"](1,2)) 3 > -- и другой вариант функции в качестве ключа > t = {} > function v(x) >> print(x) >> end > t[v] = "The Big Store" > for key,value in t do key(value) end The Big Store

Как вы могли ожидать, Lua также предоставляет несколько функций-итераторов для обработки таблиц. Функции предоставляет глобальная переменная table (да, Lua-пакеты - это тоже просто таблицы). Некоторые функции, например table.foreachi() , ожидают непрерывный диапазон целых ключей, начиная с 1 (цифра один):

> table.foreachi(t1, print) 1 moustache 2 3

Другие, например table.foreach() , выполняют итерацию по всей таблице:

> table.foreach(t2,print) 1 groucho 3 chico 5 harpo > table.foreach(t1,print) 1 moustache 2 3 brothers true

Хотя некоторые итераторы оптимизированы для целых индексов, все они просто обрабатывают пары (ключ, значение).

Ради интереса создайте таблицу t с элементами {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="www.lua.org"} и выполните команды table.foreach(t, print) и table.foreachi(t, print) .

Userdata

Поскольку Lua предназначен для встраивания в базовое приложение, написанное на таких языках, как, например, C или C++, для взаимодействия с базовым приложением данные должны совместно использоваться средой C и Lua. Как указано в "Справочном руководстве по Lua 5.0 ", тип userdata позволяет "произвольным C-данным храниться в Lua-переменных". Вы можете рассматривать тип userdata как массив байтов - байтов, которые могут представлять указатель, структуру или файл в базовом приложении.

Содержимое userdata происходит от C, поэтому оно не может быть модифицировано в Lua. Естественно, поскольку userdata происходит от C, в Lua не существует предопределенных операций для userdata. Однако вы можете создать операции, которые работают с userdata , используя еще один механизм Lua, называемый мета-таблицами (metatables).

Мета-таблицы

Из-за такой гибкости типов table и userdata Lua разрешает перегружать операции для объектов каждого из этих типов (вы не можете перегружать шесть остальных типов). Мета-таблица - это (обычная) Lua-таблица, которая отображает стандартные операции в предоставляемые вами пользовательские функции. Ключи мета-таблицы называются событиями (event); значения (другими словами, функции) называются мета-методами (metamethod).

Функции setmetatable() и getmetatable() изменяют и запрашивают мета-таблицу объекта соответственно. Каждый объект table и userdata может иметь свою собственную мета-таблицу.

Например, одним из событий является __add (для добавления). Можете ли вы определить, что делает следующая порция?

-- Перегрузить операцию add -- для конкатенации строк -- mt = {} function String(string) return setmetatable({value = string or ""}, mt) end -- Первый операнд - это String table -- Второй операнд - это string -- .. - это операция конкатенации в Lua -- function mt.__add(a, b) return String(a.value..b) end s = String("Hello") print((s + " There " + " World!").value)

Эта порция отображает следующий текст:

Hello There World!

Функция function String() принимает строку (string), заключает ее в таблицу ({value = s or ""}) и назначает мета-таблицу mt этой таблице. Функция mt.__add() является мета-методом, добавляющим строку b к строке, находящейся в a.value b раз. Строка print((s + " There " + " World!").value) активизирует мета-метод дважды.

Index - это еще одно событие. Мета-метод для __index вызывается всегда, когда ключ в таблице не существует. Вот пример, который запоминает ("memoizes") значение функции:

-- код, любезно предоставленный Рики Лэйком (Rici Lake), [email protected] function Memoize(func, t) return setmetatable(t or {}, {__index = function(t, k) local v = func(k); t[k] = v; return v; end }) end COLORS = {"red", "blue", "green", "yellow", "black"} color = Memoize(function(node) return COLORS end)

Поместите этот код в Lua-интерпретатор и введите print(color, color, color) . Вы должны увидеть что-то подобное blue black blue .

Этот код, получающий ключ и узел, ищет цвет узла. Если он не существует, код присваивает узлу новый, выбранный случайно цвет. В противном случае возвращается цвет, назначенный узлу. В первом случае мета-метод __index выполняется один раз для назначения цвета. В последнем случае выполняется простой и быстрый поиск в хеш-таблице.

Язык Lua предлагает много мощных функциональных возможностей, и все они хорошо документированы. Но всегда, когда вы столкнетесь с проблемами или захотите пообщаться с мастером, обратитесь за поддержкой к энтузиастам - IRC-канал Lua Users Chat Room (см. раздел " ").

Встроить и расширить

Кроме простого синтаксиса и мощной структуры таблиц, реальная мощь Lua очевидна при использовании его совместно с базовым языком. Как уже говорилось, Lua-сценарии могут расширить собственные возможности базового языка. Но справедливо также и обратное - базовый язык может одновременно расширять Lua. Например, C-функции могут вызывать Lua-функции и наоборот.

Сердцем симбиотического взаимодействия между Lua и его базовым языком является виртуальный стек . Виртуальный стек (как и реальный) является структурой данных "последний вошел - первый вышел" (last in-first out - LIFO), которая временно сохраняет аргументы функции и ее результаты. Для вызова из Lua базового языка (и наоборот) вызывающая сторона помещает значения в стек и вызывает целевую функцию; принимающая сторона достает аргументы из стека (конечно же, проверяя тип и значение каждого аргумента), обрабатывает данные и помещает в стек результаты. Когда управление возвращается вызывающей стороне, она извлекает значения из стека.

Фактически, все С-интерфейсы прикладного программирования (API) для Lua-операций работают через стек. Стек может хранить любое Lua-значение; однако тип значения должен быть известен как вызывающей стороне, так и вызываемой, а конкретные функции помещают в стек и извлекают из него каждый тип (например, lua_pushnil() и lua_pushnumber()).

В листинге 2 показана простая C-программа (взятая из главы 24 книги "Программирование в Lua ", ссылка на которую приведена в разделе " "), реализующая минимальный, но функциональный Lua-интерпретатор.

Листинг 2. Простой Lua-интерпретатор
1 #include 2 #include 3 #include 4 #include 5 6 int main (void) { 7 char buff; 8 int error; 9 lua_State *L = lua_open(); /* открывает Lua */ 10 luaopen_base(L); /* открывает основную библиотеку */ 11 luaopen_table(L); /* открывает библиотеку table */ 12 luaopen_io(L); /* открывает библиотеку I/O */ 13 luaopen_string(L); /* открывает библиотеку string */ 14 luaopen_math(L); /* открывает библиотеку math */ 15 16 while (fgets(buff, sizeof(buff), stdin) != NULL) { 17 error = luaL_loadbuffer(L, buff, strlen(buff), "line") || 18 lua_pcall(L, 0, 0, 0); 19 if (error) { 20 fprintf(stderr, "%s", lua_tostring(L, -1)); 21 lua_pop(L, 1); /* извлечь сообщение об ошибке из стека */ 22 } 23 } 24 25 lua_close(L); 26 return 0; 27 }

Строки с 2 по 4 включают стандартные Lua-функции, несколько удобных функций, используемых во всех Lua-библиотеках, и функции для открытия библиотек, соответственно. Строка 9 создает Lua-структуру . Все структуры сначала пусты; вы добавляете библиотеки или функции к структуре при помощи luaopen_...() , как показано в строках с 10 по 14.

В строке 17 luaL_loadbuffer() принимает входную информацию с stdin в виде порции и компилирует ее, помещая порцию в виртуальный стек. Строка 18 извлекает порцию из стека и выполняет ее. Если во время исполнения возникает ошибка, Lua-строка помещается в стек. Строка 20 обращается к вершине стека (вершина стека имеет индекс -1) как к Lua-строке, распечатывает сообщение и удаляет значение из стека.

Используя C API, ваше приложение может также "достать" информацию из Lua-структуры. Следующий фрагмент кода извлекает две глобальные переменные из Lua-структуры:

.. if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0)) error(L, "cannot run configuration file: %s", lua_tostring(L, -1)); lua_getglobal(L, "width"); lua_getglobal(L, "height"); .. width = (int) lua_tonumber(L, -2); height = (int) lua_tonumber(L, -1); ..

Опять же, обратите внимание на то, что передачу разрешает стек. Вызов любой Lua-функции из C аналогичен следующему коду: извлечь функцию при помощи lua_getglobal() , поместить аргументы, выполнить lua_pcall() и обработать результаты. Если Lua-функция возвращает n значений, первое значение находится по индексу -n в стеке, а последнее - по индексу -1 .

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

Lua великолепен

Lua - это чрезвычайно легкий в использовании язык, но его простой синтаксис маскирует его мощь: язык поддерживает объекты (аналогичные объектам Perl), мета-таблицы делают его тип table абсолютно гибким, а C API разрешает отличную интеграцию и расширение сценариев и базового языка. Lua может использоваться совместно с языками C, C++, C#, Java™ и Python.

Перед созданием еще одного формата конфигурационного файла или ресурса (и еще одного синтаксического анализатора для него) попробуйте Lua. Язык Lua (так же как и его сообщество) надежен, изобретателен и готов прийти на помощь.

Lua - язык программирования, создателями которого являются Роберту Иерузалимски, Валдемар Селиш и Луис Энрике ди Фигейреду. С трудом верится, что такой популярный язык могли создать не где-нибудь в Кремниевой Долине или MIT, а в солнечной Бразилии. В стране, которая, казалось бы, находится довольно далеко от центров сосредоточения IT. Тем не менее, в одном из подразделений Католического университета Рио-де-Жанейро смогли создать настолько гибкий и мощный язык, что сейчас он находит широкое применение во многих областях.

Всё началось с разработки вспомогательного языка для нефтяной компании PETROBRAS. Инженерам-нефтяникам требовался графический фронтэнд для обработки данных по симуляции определенных процессов. При этом оборудование могло быть самым разным - и PC DOS, и UNIX, Macintosh, поэтому многие уже существующие языки (Perl, например) просто не подходили, так как работали только на одной из этих систем. На этом этапе был разработан язык под названием DEL (data entry language). Со временем, возможностей этого языка стало не хватать, поэтому был разработан новый язык, названный SOL (simple object language). И, наконец, в 1993 году разработчики поняли, что их можно объединить в один полноценный язык программирования, которые был назван Lua (по-португальски Sol это солнце, а Lua - луна). Кстати, в 1996 году Роберту Иерузалимски и другие авторы языка решили рассказать о своей работе миру и отправили статью про Lua в журнал “Software: Practice & Experience”. Позже про Lua напечатали в журнале “Dr.Dobb’s”, из которого о нем узнал один из главных разработчиков адвенчурных игр в LucasArts. Решив использовать Lua вместо их собственного скриптового языка, он был поражен его простотой и эффективностью. В результате этого большая часть разрабатываемой в тот момент игры была переписана на Lua, что способствовало росту его популярности.

Философия языка Lua

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

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

Стоит упомянуть такжи и о метатаблицах - таблицы, которые позволяют изменять поведение других таблиц. Например, определить, допустимо ли в некоторой ситуации сложение нечисловых значений. Или определить для некоторого события запуск “сборки мусора” (очистки памяти).

Где применяется Lua

Хотя Lua используется и в промышленных приложениях,но самую большую популярность этот язык приобрел в геймдеве. Так как разработчикам бывает трудно вносить изменения в движок игры, а геймдизайнерам постоянно приходится вносить изменения в работу уровней или персонажей, то здесь Lua бывает просто незаменим. На нем очень легко в описать взаимодействие между игроками, запрограммировать NPC (крестьян в скайриме) или поведение боссов при помощи скриптов, которые потом можно быстро изменить, не влияя на движок.

Самой известной игрой, в которой применяется Lua, сейчас, конечно, стала World of Warcraft. Интерфейс WoW (меню, чат и.т.д) написаны на нем. Ещё Lua использовали в таких играх, как Crysis, King’s of Bounty, Warhammer, Аллоды онлайн, CS, Сталкер, Ведьмак, Sim City, Far Cry, Civilization V и.т.д.

Ещё на Lua часто пишутся плагины для nmap, wireshark, nginx или боты для Telegram. А ещё Википедия планирует использовать Lua для встраивания в MediaWiki (можете попробовать в английской версии).

Lua также используется в обсерваториях, занимающихся исследованиями в области астрофизики и крупных университетах по всему миру (например, в Берлинском Техническом Университете). Также Lua стал чем-то вроде национального языка программирования у себя на родине и используется многими местными компаниями и исследовательскими центрами в самых разных сферах деятельности.

Сложность обучения Lua

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

Плюсы/минусы Lua

К плюсам Lua относятся:

  • хорошая портируемость. Если вам потребуется, например, перенести программу из Windows в Linux, то, за исключением некоторых специфичных для платформ библиотек, код не потребуется сильно изменять.
  • возможность быстро добавить к приложению на Lua библиотеку на С
  • легкость развертывания программ
  • легкий синтаксис
  • программы на Lua потребляют мало памяти
  • распространяется по лицензии MIT, поэтому можно бесплатно использовать и для бизнес проектов

Из минусов:

Lua отлично работает настолько, насколько вообще может скриптовый язык. Но чаще всего его применяют совместно с другими языками, хотя он вполне выполнять некоторые задачи самостоятельно. Поэтому, вам нужно будет знать хотя бы ещё один, например,C или С++. Однако, несомненно, знание Lua будет вам большим плюсом при трудоустройстве на должность разработчика игр.

Сопутствующие технологии

LuaJIt - JIT-компилятор для Lua. Используется для задач, в которых критично время выполнения. Работает примерно в шесть раз быстрее стандартного интерпретатора.

Love2D - популярный фреймворк, предназначенный для разработки 2D игр на Lua.

Corona SDK - фреймворк для создания приложений под iOS и Android на Lua. С 2015 года появилась бесплатная версия.

Наш сегодняшний гость - настоящий боец скрытого фронта. Вы могли видеть его в играх (World of Warcraft, Angry Birds, X-Plane, S.T.A.L.K.E.R.) или продуктах компании Adobe (Lightroom), но даже не задумывались о его существовании. Между тем этому языку уже почти 25 лет и всё это время он незаметно делал нашу виртуальную жизнь чуть лучше.

Краткая справка

Lua бы придуман в 1993 году в Католическом университете Рио-де-Жанейро. Название переводится с португальского, как Луна, причем создатели убедительно просят не писать LUA, чтобы, не дай Бог, кто-нибудь не принял название за аббревиатуру. Является мультипарадигмальным скриптовым языком, использующим прототипную модель ООП.

Типизация здесь динамическая, а для реализации наследования используются метатаблицы, то есть это прекрасный инструмент для расширений возможностей вашего продукта. Причем из-за своей компактности он пригоден для использования практически на любой платформе. Посудите сами: tarball Lua 5.3.4 весит всего 296 килобайт (в “разжатом” виде - 1.1 мегабайт), интерпретатор (написанный на C) для Linux - от 182 до 246 килобайт, а стандартный набор библиотек - ещё 421 килобайт.

Код

По внешнему виду, да и возможностям Lua похож на очередную попытку переделать JavaScript, если бы не тот факт, что последний появился на два года позднее. Смотрите сами:

Начнем с традиционного:

print("Hello World")

Согласитесь, знакомо и не слишком информативно. Более интересный пример с точки зрения знакомства с Lua - вычисление факториала введенного числа:

Function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end

Print("enter a number:")
a = io.read("*number") -- read a number
print(fact(a))

Все предельно понятно. Кстати, в Lua поддерживается параллельное присваивание:

И в заключении довольно простой пример с использованием библиотек:

#include
#include
#include
#include
#include

Int main (void) {
char buff;
int error;
lua_State *L = lua_open(); /* opens Lua */
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */

While (fgets(buff, sizeof(buff), stdin) != NULL) {
error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
lua_pcall(L, 0, 0, 0);
if (error) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
}
}

Lua_close(L);
return 0;
}

Преимущества и недостатки

Итак, чем же хорош Lua?

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

Среды разработки

LDT (Lua Development Tools) для Eclipse - расширение для одной из наиболее популярных IDE;

ZeroBrane Studio - специализированная среда, написанная на Lua;

Decoda - не самая популярная кроссплатформенная IDE, но в качестве альтернативы подойдет;

SciTE - хороший редактор, полноценно поддерживающий Lua;

WoWUIDesigner - угадайте, для какой игры эта среда помогает обрабатывать скрипты, в том числе на Lua?

Полезные ссылки

http://www.lua.org/home.html - официальный сайт со всей необходимой информацией, учебником, книгами, документацией и даже есть немного специфического юмора;

http://tylerneylon.com/a/learn-lua/ - отличная обучалка от Tyler Neylon. Подойдет программистам с опытом, кто хорошо знает английский язык (впрочем, со словарем тоже не возникнет больших проблем) и просто желает расширить свой кругозор;

https://zserge.wordpress.com/2012/02/23/lua-за-60-минут/ - основы Lua за 60 минут от явно неравнодушного к этому языку программиста. На русском языке;

http://lua-users.org/wiki/LuaTutorial - вики-учебник;

https://youtube.com/watch?v=yI41OL0-DWM - видеоуроки на YouTube, которые помогут вам наглядно разобраться с настройкой IDE и базовыми принципами языка.

LUÁ, iau, vb. I. tranz. I. 1. A prinde un obiect în mână spre a l ţine (şi a se servi de el) sau spre a l pune în altă parte. ♢ expr. A lua altă vorbă = a schimba (cu dibăcie) subiectul unei discuţii. A(şi) lua picioarele la spinare = a pleca… … Dicționar Român

Lua - Logo Basisdaten Paradigmen: Skriptsprache, imperativ, funktional, objektorientiert … Deutsch Wikipedia

Lua - [] Información general Paradigma Multiparadigma: interpretado, imperativo, funcional, orientado a objetos, basado en prototipos Apareció en … Wikipedia Español

LUA - Apparu en 1993 Auteur Luiz Henrique de Figueiredo, Roberto Ierusalimschy et Waldemar Celes Implémentations Lua, LuaJIT, LLVM Lua, LuaCLR, Nua, Lua A … Wikipédia en Français

LUA - (portugiesisch für Mond) ist eine Skriptsprache zum Einbinden in Programme, um diese leichter weiterentwickeln und warten zu können. Eine der besonderen Eigenschaften von Lua ist die geringe Größe des kompilierten Skript Interpreters. Lua wurde… … Deutsch Wikipedia

lua - s. f. 1. O único planeta satélite da Terra. 2. Tempo compreendido entre dois novilúnios. 3. Mês. 4. Cio. 5. O mesmo que peixe lua. 6. Disco de ouro ou prata que os Timores usam ao pescoço, como símbolo de… … Dicionário da Língua Portuguesa

Lua - may refer to: * Lua (programming language), a lightweight, extensible programming language * Lua (Yu Gi Oh! 5D s) * Lua (goddess), the Roman goddess * Lua (martial art), a traditional Hawaiian martial art * Lua (song), a single by the folk rock… … Wikipedia

LUA аббревиатура: LUA последний всеобщий предок (также переводится как «Последний универсальный предок» (англ. LUA, Last Universal Ancestor), иначе Последний универсальный общий предок (англ. LUCA, last universal common… … Википедия

lúa - (Del gót. lôfa, palma de la mano). 1. f. Especie de guante hecho de esparto y sin separaciones para los dedos, que sirve para limpiar las caballerías. 2. Mar. Revés de las velas por la parte donde van cazadas con viento largo o en popa. 3. Mar.… … Diccionario de la lengua española

Lua - Lua, römische Göttin, Tochter des Saturnus, welcher nach der Schlacht zur Sühne des vergossenen Blutes erbeutete Waffen von dem Feldherrn verbrannt wurden … Pierer"s Universal-Lexikon

LUA - Dea quaedam apud vett, a luendo, expiandoque nomen sortita, quae praeerat lustrationibus, et lustris. Vide Turneb. Adver s. l. 16. c. 20. et l. 23. c. 23. et l. 19. c. 11. Eius meminit A. Gell. l. 13. c. 22. cum ait in libris Sacerdotum Pop. Rom … Hofmann J. Lexicon universale

Книги

  • Программирование на языке Lua , Иерузалимски Роберту. Книга посвящена одному из самых популярных встраиваемых языков - Lua. Этот язык использовался во многих играх и большом количестве различных приложений. Язык сочетает небольшой объем…
  • Программирование на языке Lua. 3-е издание , Иерузалимски Р.. Книга посвящена одному из самых популярных встраиваемых языков - Lua. Этот язык использовался во многих играх и большом количестве различных приложений. Язык сочетает небольшой объем…

Всем привет.

Сегодня мы поверхностно пройдёмся по языку Lua, его некоторым возможностям, а так же запуске наших сценариев в RakBot.
Lua - скриптовый язык программирования, предназначен для быстрой обработки данных. С помощью данного языка многие разработчики создают искусственный интелект в играх, пишут алгоритмы генерации уровней, а так же он используется для разработки ресурсов/игровых модов в Multi Theft Auto: San Andreas (аналог SA:MP). На самом деле, это простейший язык и с помощью него мы будем учиться писать собственную логику для ботов, которую будет использовать RakBot.

Пройдёмся по основам программирования, с которыми нам предстоит работать.

Обратите внимание : данная статья будет урезана в плане языка Lua, так как в RakBot используется лишь небольшая её часть. Многие возможности Lua попросту отсустствуют в RakBot, поэтому я буду ориентироваться на версию из RakBot.

Есть традиция у всех авторов книг и документаций различных языков, это первая программа, которая печатает "Hello World".
Чтож, давайте попробуем написать её, но уже в RakBot. Переходим на оффициальный сайт RakBot и ищем раздел "Доступные функции", раздел "События".

Нам необходимо событие onScriptStart() , которые вызывается автоматически при загрузке скрипта самим RakBot"ом.

В этой функции нам необходимо описать логику, которая будет писать в чат-лог RakBot"a "Hello World". Для этого, на той же странице в документации, посмотрим на раздел "Функции".

Первая фукнция printLog(text) - это то, что нам и нужно. С помощью этой функции мы отправим сообщение в чат RakBot"а. Для этого мы напишем:

Мы написали логику в каком-то текстовом документе, но как сказать RakBot, чтобы он выполнил наш сценарий? Для этого необходимо сохранить файл с расширением .lua и положить его в папку scripts , в папке с RakBot.
Я сохранил текстовый документ с именем "example.lua ". Давайте попробуем запустить RakBot и посмотреть, что у нас получилось.

Как мы видим, при запуске RakBot, он находит скрипт "example.lua ", после чего выполняет его. Из этого мы можем сделать вывод, что инициализация сценария происходит при запуске самого RakBot или при перезагрузке всех сценариев командой !reloadscripts .

Поздравляю, Вы только что написали свой собственный сценарий для RakBot!

Мы уже научились писать Hello World в консоли RakBot"а, но мы хотим писать сложных ботов, которые будут делать всю работу за нас, учитывая те или иные условия. На этом мы остановимся.
Практически всё, что происходит в программировании, можно описать следующим образом: возьми данные, что-то с ними сделай, отдай результат.
В данном случае данными выступает сам RakBot. Он сам запускает наши сценарии, а так же сам передаёт нам данные, которые мы можем обработать так, как хотим и в конце получить результат.

Давайте напишем простейший сценарий с условием. Условием будет являться ник бота. Если ник бота "СМaster", значит мы выведем в чат RakBot"а "CM FOREVER", если же ник бота совершенно другой - выведем в чат "Nonamer".
Для этого нам поможет условный оператор if else , он же оператор ветвления. Он принимает на себя условие, которое должно вернуть либо true , либо false . Если условие равно true , тогда код внутри будет выполнен, если false - не будет выполнен.
На этом строится большая часть логики любого приложения. Дословно if переводится как "ЕСЛИ", then - "ЗНАЧИТ", else - "ИНАЧЕ" Если это сильно сложно - не переживайте, Вы поймёте всё дальше.

В Lua есть следующие операторы сравнения:
> Больше
< Меньше
>= Больше или равно
<= Меньше или равно
~= Не равно
== Равно

Если мы напишем "CMaster " == "CM " - у нас будет значение False , то есть, ложь
Если мы напишем "CMaster " == "CMaster " - у нас будет значение True , то есть, истина.

5 > 10 -- ложь 5 < 10 -- истина 10 ~= 15 -- истина 10 >= 5 -- истина

Попробуем использовать логику ветвления в нашем предыдущем сценарии.

Тот код, который мы писали ранее:

Function onScriptStart() printLog("Hello world!"); end

Преобразуем следующим образом:

Function onScriptStart() botName = getNickName() if(botName == "CMaster") then printLog("CM FOREVER"); else printLog("Nonamer"); end end

Давайте разберём этот код начиная сверху. Я советую сразу начинать учить читать код. Поэтому попробуем прочитать, что у нас получилось

Function onScriptStart() - создаём фукнцию с именем onScriptStart botName = getNickName() - в переменную botName записываем имя бота if(botName == "CMaster") then - если имя бота равно "CMaster", значит printLog("CM FOREVER"); - пишем в чат "CM Forever". else- ИНАЧЕ, или же если имя бота НЕ РАВНО "CMaster" printLog("Nonamer"); - пишем в чат "Nonamer" end- конец условий end- конец функции

Давайте попробуем проверить код, который мы написали. Я сохранил измененный код так же под именем "example.lua " и запустил RakBot с ником "Mason_Bennett ".

После загрузки нашего сценария, RakBot написал в чат Nonamer. Попробуем зайти с ником "CMaster ".

Как мы видим, наше условие успешно работает и мы видим в чате то, что и хотели.

Пройдёмся немного по переменным. У Вас есть лист бумаги и Вы хотите его сохранить. Сохранить каким образом - куда-то положить, чтобы не потерять его. Например, мы можем положить наш лист бумаги в шкафчик и достать тогда, когда нам будет необходимо. Если у нас будет новый листок и нам не нужен будет старый - мы выкинем старый листок и положим новый.
Это и есть логика переменной. Мы можем создавать переменную с именами, которыми хотим и записывать в них значения, что мы и сделали в предыдущем примере с переменной botName.

В Lua мы можем записывать в переменную всё, что мы хотим. Например, я хочу создать переменную с именем PaperList и записать в неё текст "Lua - урок №2 ". Для этого я напишу:

PaperList = "Lua - урок №1"

Что мы здесь сделали? Написали имя и использовали оператор присваивания "=" и теперь я могу использовать эту переменную в любом месте своего сценария.
Думаю, что если Вы вспомните математику на уровне максимум 5 класса - тут будет всё понятно.

У Lua есть несколько типов переменных, это nil, boolean, number, string . Не бойтесь, это всё очень просто.

На самом деле их несколько больше, но я уже говорил, что в RakBot большая часть функционала отсутствует.

nil - отсуствие значения.
boolean - логические значения, принимает два варианта значений - либо true, либо false.
number - вещественное число с двойной точностью. В Lua нет целочисленного типа, поэтому он выступает в качестве и вещественного и целочисленного типа.
string - строка, здесь, я думаю, всё понятно.
Чтож, давайте попробуем создать несколько переменных и "поиграться" с ними.

number = 0; - создаём переменную с именем number и присваиваем значение 0
number = number + 5; - присваивание значения переменной number + 5 (то есть, 0 + 5), теперь у нас хранится здесь число 5.
number ++; - ++ - инкремент. Другими словами - вы берёте переменную и увеличиваете её на одну единицу. То есть (5 + 1) - теперь 6 лежит у нас в переменной number.
number --; - -- декремент. Другими словами - уменьшаем на одну единицу. (6 - 1) - теперь значение равно 5.

string = "Hello" - создаём переменную string со значением "Hello"
string = string .. "," - конкатенация строк, оно же сложение строк. Что мы здесь сделали? Указани имя переменной, указали оператор конкатенации ".. ", после чего указали ещё одну строку, которую необходимо добавить к первой. Теперь у нас в переменной "string " лежит значение "Hello,".
string = string .. getNickName () - теперь, к "Hello," мы добавили ник бота, пускай будет "Michel". Теперь у нас в переменной string лежит значение "Hello,Michel".

boolean = true ; - создаём переменную boolean со значением true (ИСТИНА).
boolean = getNickName () == "Dimosha" - сравниваем имя бота со строкой Dimosha. Так как имя бота у нас Michel, из предыдущего примера, сюда запишется значение false (ЛОЖЬ).

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

Давайте пройдёмся по самому простому пути: фукнция без параметров и без возвращаемого значения, которая будет складывать 5 + 10 и выводить результат в консоль RakBot"а.

Я создам функцию с именем Add :

Function Add() -- Создаём фукнцию Add printLog(5 + 10) -- используем метод RakBot для вывода в консоль end-- Конец функции

Мы создали не совсем универсальную фукнцию по двум причинам:
- если мне нужно будет складывать другие числа - мне придётся создавать ещё одну такую же фукнцию
- я не могу использовать полученное значение за пределами фукнции

Попробуем исправить первый недочёт. Для этого мы добавим два параметра в фукнцию, которые будут принимать на себя числа для сложения. Сделаем мы это следующим образом:

Function Add(a, b) printLog(5 + 10) end

Теперь в методе у нас доступны два значения, которые содержатся в двух новых переменных a и b, но на консоль у меня всё равно выводится 15. Исправим это:

Function Add(a, b) printLog(a + b) end

Идеально. Теперь, при вызове этого метода, мы будем получать результат сложения в консоли. Попробуем протестировать. Изменим наш код в example.lua на следующий:

Function Add(a, b) printLog(a + b) end function onScriptStart() Add(5, 10); Add(123, 4324); Add(555, 111); end

И попробуем запустить RakBot. Посмотрим, что из этого получится:

Это решило нашу первую проблему. Попробуем решить вторую, чтобы наша функция возвращала результат.

Перепишем фукнцию Add :

Function Add(a, b) return a + b end

return - ключевое слово для возвращения значения из функции. Перепишем теперь метод onScriptStart :

Function onScriptStart() printLog("Первое значение: "..Add(5, 10)); printLog("Второе значение: "..Add(123, 4324)); printLog("Третье значение: "..Add(555, 111)); end

Посмотрим, что получилось.

Мы могли создать три переменные, присвоив им значения из фукнций Add и после их передавать в метод printLog , но я не стал этого делать, так как код выглядит более читабельным и приятнее.

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