
Lua — это скриптовый язык, разработанный в Бразилии в начале 1990-х годов. Интерпретатор Lua переводит исходный текст программы Lua в байткод и затем выполняет ее. Сам интерпретатор написан на языке C, что обеспечивает большую производительность программ Lua во время выполнения. Более того, C-API позволяет встраивать код Lua в программы на C/C++. Lua — это мультипарадигмальный язык, подходящий для написания императивного, функционального и объектно-ориентированного кода.
Сильнейшим отличием Lua является простота встраивания в другие системы и языки. В результате Lua зарекомендовал себя как «язык-клея» и используется во многих игровых движках. Более того, этот язык можно использовать для управления веб-серверами, такими как Apache и nginx. Благодаря интерфейсу CGI, Lua также часто используется как самостоятельный язык интернет-программирования. Кроме того, язык используется для программирования мобильных приложений.
- Самоучитель по написанию сценариев на языке Lua: первые шаги
- Подготовка системы к работе с учебником Lua
- Использование интерпретатора Lua в интерактивном режиме
- Запуск сценария Lua для учебника с помощью интерпретатора Lua
- Создание непосредственно исполняемого Lua-скрипта для учебника с помощью хэшбэнга
- Изучение основ языка сценариев Lua
- Учимся использовать комментарии в скриптах Lua
- Значения и типы для учебника по кодированию на языке Lua
- Изучение кода на языке Lua: Что такое выражения, переменные и операторы?
- Понимание диапазонов достоверности и блоков для учебника по программированию на Lua
- Обучение программированию с использованием управляющих структур Lua
- Узнайте больше о функциях в Lua
Самоучитель по написанию сценариев на языке Lua: первые шаги
Самый простой и быстрый способ научиться программировать на Lua — это выполнить код Lua на интерактивном демонстрационном сайте Lua. Вы можете протестировать все примеры кода Lua, представленные далее в этой статье. Скопируйте один из примеров кода в текстовое поле и нажмите кнопку «run», чтобы выполнить код.
Это означает, что вам не нужно ничего устанавливать. Если вы хотите использовать Lua на своей системе, следуйте нашим инструкциям ниже. В противном случае перейдите к разделу «Изучение основ языка сценариев Lua».

Подготовка системы к работе с учебником Lua
Интерпретатор Lua состоит из одного двоичного файла, доступного в командной строке после ввода команды «lua». Он сохраняется в системе и может потребоваться при вводе пути. Кроме того, Lua предлагает библиотеки, позволяющие встраивать код Lua в программы на C/C++.
Менеджер пакетов «Homebrew» может быть использован для установки на системы Mac и Linux. Если вы установили Homebrew на свою систему, введите в командную строку следующую инструкцию для установки Lua:
brew install lua
Для установки Lua в системе Windows вы можете обратиться к программе установки LuaDist.
Использование интерпретатора Lua в интерактивном режиме
Как и во многих скриптовых языках, интерпретатор Lua можно запускать в интерактивном режиме. В интерактивном режиме интерпретатор принимает код Lua в командной строке и выполняет его строка за строкой. Сгенерированные таким образом значения выводятся непосредственно в командную строку. Как пользователь, вы можете проверять и корректировать значения переменных. Поэтому такой подход особенно подходит для быстрого создания прототипов. Чтобы запустить интерпретатор Lua в интерактивном режиме, введите в командную строку следующую команду:
# Start Lua interpreter in interactive mode
lua -i
Чтобы выйти из интерактивного режима, введите команду «os.exit()» или нажмите вместе клавиши [Ctrl]+[D].

Запуск сценария Lua для учебника с помощью интерпретатора Lua
Вместо того чтобы вводить код Lua по частям в командной строке, вы также можете указать интерпретатору Lua запустить полный текстовый файл с исходным текстом Lua. Для этого мы сначала создаем файл Lua и передаем имя файла интерпретатору Lua для выполнения. Затем интерпретатор считывает исходный текст, содержащийся в файле, строка за строкой и выполняет его.
# Run Lua script
lua <file name>.lua
Файлы исходного текста Lua заканчиваются расширением файла «.lua».
Создание непосредственно исполняемого Lua-скрипта для учебника с помощью хэшбэнга
В операционных системах Linux / UNIX / macOS мы также можем сделать исходный текстовый файл Lua непосредственно исполняемым. Здесь мы вводим «hashbang» в качестве первой строки в файле Lua:
#!/usr/local/bin/lua
-- Lua code for execution
Как вы можете видеть, хэшбанг содержит место хранения бинарного файла Lua — в нашем примере: #!/usr/local/bin/lua. При определенных обстоятельствах место хранения может отличаться от этого в вашей локальной системе. В этом случае вы можете узнать место хранения двоичного файла Lua с помощью команды «which» в командной строке:
# Find out the storage location of the Lua binary file
which lua
После добавления хэшбанга в сценарий Lua необходимо пометить файл как исполняемый для пользователя. Для этого используйте следующую команду в командной строке:
# Mark Lua file as executable
chmod u+rx <file name>.lua
Затем запустите сценарий Lua в текущем каталоге:
./<file name>.lua

Трюк с хэшбангом работает с большинством скриптовых языков в Linux и системах типа UNIX, таких как macOS. Тот же подход позволяет сделать сценарии Ruby или Python непосредственно исполняемыми.
Изучение основ языка сценариев Lua
Lua — это мультипарадигмальный язык. Основной стиль — императивный и функциональный. Язык полностью динамический, т.е. нет различий между временем компиляции и временем выполнения. Lua использует исключительно динамическое управление памятью. Размер объекта в памяти может меняться во время выполнения. Сборщик мусора» (GC) очищает все пространство памяти, которое больше не нужно, то есть программистам не нужно самим заботиться об этом.
Учимся использовать комментарии в скриптах Lua
Комментарии являются неотъемлемой частью любого языка программирования. Они используются, в частности, для следующих целей:
- Выделение компонентов кода
- документирование особенностей кода
- Активация/деактивация строк кода
Однострочный комментарий в Lua начинается с двойного дефиса (—) и идет до конца строки:
-- this line is ignored by the interpreter
Многострочные комментарии можно писать в сочетании с двойными квадратными скобками «[[» и «]]»:
--[[
This comment
covers multiple
lines.
]]
Значения и типы для учебника по кодированию на языке Lua
Как и большинство других скриптовых языков, Lua является языком динамических типов. Типы принадлежат не переменным, а значениям. Каждое значение имеет ровно один тип — будь то число, строка символов, истинностное значение и т.д. В целом, в Lua имеется достаточное количество типов. Они представлены в следующей таблице:
Тип |
Объяснение |
число |
Десятичное число |
строка |
Строка символов |
булево |
Истинное значение: «истина» или «ложь» |
nil |
Отсутствующее значение; тип имеет только значение «nil». |
функция |
Функция |
таблица |
Комбинированный тип данных: список/массив, хэш/словарь |
поток |
Корутины |
пользовательские данные |
Определяемый пользователем тип данных C |
Lua использует литеральный синтаксис для значений всех типов, кроме «thread» и «userdata». Чтобы определить тип значения, мы используем функцию «type()». Она возвращает имя типа в виде строки. Вот несколько примеров:
type(42) -- Type is `number`
type("Lua Tutorial") -- Type is `string`
type(false) -- Type is `boolean`
type(var) -- Type is `nil`, because `var` is not defined
В следующих примерах кода имейте в виду, что в Lua первый элемент списка имеет индекс 1, а не 0, как это обычно бывает в большинстве языков!
Изучение кода на языке Lua: Что такое выражения, переменные и операторы?
Выражение оценивается интерпретатором и возвращается значение. Выражения объединяют литералы, операторы, переменные и вызовы функций. Выражения можно группировать с помощью круглых скобок «()». Будучи динамическим языком, Lua автоматически определяет тип возвращаемого значения. Вот несколько примеров выражений:
-- Arithmetic operation in Lua
1 + 2 -- evaluates to the value `3`
-- String concatenation in Lua
'Walter' .. 'White' -- evaluates to `WalterWhite`
-- String concatenation with the automation conversion of a number in Lua
‘The ' .. 3 .. ' Musketeers' -- evaluates to `The 3 Musketeers`
-- Parity test in Lua
7 == '7' -- evaluates to `false`
-- Parity test in Lua
‘small' == string.lower(‘SMALL') -- evaluates to `true`
-- Dynamic type information
type(var) == 'nil' -- evaluates to `true`, because `var` is not defined
Переменная — это имя для значения в памяти. Как и в большинстве языков программирования, имя в Lua начинается с буквы или знака подчеркивания (_), за которым следуют другие буквы, знаки подчеркивания или цифры. Здесь проводится четкое различие между верхним и нижним регистром. Следующие зарезервированные слова не могут быть использованы в качестве имени:
«and», «end», «in», «repeat», «break», «false», «local», «return», «do», «for», «nil», «then», «else», «function», «not», «true», «elseif», «if», «or», «until», «while».
Однако зарезервированные слова могут появляться как часть имени без каких-либо проблем:
for = "Peter" -- produces an error
for_user = "Peter" -- allowed
Значение присваивается переменной с помощью оператора присваивания (=). Его не следует путать с оператором логического равенства (==). Как обычно, при присваивании делается различие между значением «L» и значением «R». Переменная должна находиться слева от оператора присваивания, т.е. это значение «L». Справа ей присваивается оцененное значение R-значения:
number = 13 -- this is OK
13 = number -- produces an error, because the number 13 cannot be assigned a new value
Оператор генерирует новое значение из одного или нескольких операндов. Здесь мы имеем в виду унарный (однозначный) или бинарный (двузначный) оператор. Оператор объединяет операнды определенного типа и возвращает значение определенного типа. Давайте рассмотрим различные операторы в Lua.
Арифметические операторы работают с числами и возвращают число:
Арифметический оператор |
Arity |
Операция |
+ |
Двоичный |
Сложение |
— |
Двоичные |
Вычитание |
* |
Двоичное |
Умножение |
/ |
Двоичное |
Деление |
% |
Двоичный |
Модуль |
^ |
Двоичный |
Потенцирование |
— |
Унарный |
Отрицание |
Все реляционные операторы являются бинарными и проверяют, как два операнда соотносятся друг с другом. Они возвращают истинностное значение:
Реляционный оператор |
Тест |
== |
Четность |
~= |
Нечетность |
> |
Больше, чем |
< |
Меньше, чем |
>= |
Больше или равно |
<= |
Меньше или равно |
Логические операторы объединяют истинностные значения и возвращают новое истинностное значение:
Логический оператор |
Arity |
Операция |
и |
Двоичный |
комбинация И |
или |
Двоичная |
комбинация ИЛИ |
не |
Унарный |
Отрицание |
Помимо вышеперечисленных операторов, в Lua есть два специальных оператора. Они используются для конкатенации строк и определения мощности комбинированного значения, например, таблицы или строки:
Оператор |
Arity |
Оператор |
.. |
Двоичный |
Конкатенация строк |
# |
Унарный |
Определение количества элементов таблицы / длины строки |
В Lua не используются комбинированные операторы распределения, такие как «+=» и «-=», которые обычно можно встретить во многих скриптовых языках. Для инкремента и декремента переменных операция записывается в явном виде:
price = 42.99
discount = 0.15 -- 15% discount
price -= price * discount -- `-=` does not work in Lua
-- Decrementation must instead be written out explicitly
price = price - (price * discount)
Понимание диапазонов достоверности и блоков для учебника по программированию на Lua
Понятие диапазона достоверности важно для любого языка программирования. Переменная существует только в определенном допустимом диапазоне. Как и в JavaScript, переменные в Lua по умолчанию являются глобальными. Однако постоянное использование глобальных переменных известно как «антипаттерн», и его следует избегать. В Lua можно найти решение в виде ключевого слова «local». Это позволяет ограничить область действия переменной окружающим блоком — сравнимо с объявлением через «let» в JavaScript.
-- This variable is global
x = 5
-- Define a local variable
local z = 10
Тела функций и циклов открывают новый диапазон действия в Lua. Кроме того, в Lua используется концепция явного блока. Блок определяет новый диапазон действия для кода между ключевыми словами «do» и «end». Это соответствует открытым/закрытым скобкам «{» и «}» в Java/C/C++. Следующий пример кода показывает, как блоки, диапазоны действительности и переменные связаны друг с другом:
-- Outer validity range
do
local x = 1
do -- inner validity range
local y = 2
-- Generate `z` in the global validity range
-- access local variable `x` from the outer validity range
-- and local variable `y` from the inner validity range
z = x + y -- `z` now has the value `3`
end
print(x) -- outputs `1`
print(y) -- outputs `nil`, because `y` does not exist in the outer validity range
print(z) -- outputs `3`
end
-- `z` is global, i.e. it exists outside the outer validity range
z = z + 4
print(z) -- outputs `7`
Обучение программированию с использованием управляющих структур Lua
Lua предлагает обычные управляющие структуры, которые можно найти и в других языках программирования. К ним относятся ветвления и циклы. Вот пример инструкций Lua «if», «then», «else» и «elseif»:
limit = 42;
number = 43;
if number < limit then
print("Under the limit.")
elseif number == limit then
print("Right on the limit…")
else
print("Over the limit!")
end
Помимо классического цикла «while», Lua также распознает его аналог «repeat» «until». Эта инструкция также встречается в Ruby. Она требует отмены используемого условия. Это означает, что «while» с условием «число </= limit» соответствует «repeat» «until» с условием «число > limit». Будьте осторожны при использовании инструкции «repeat»! Независимо от условия, тело цикла выполняется как минимум один раз. Вот пример:
limit = 10
number = 1
while number <= limit do
print("Number:", number)
number = number + 1
end
-- Attention: although `number` is already larger than `limit`
-- the loop body is executed once
number = 11
repeat
print("Number:", number)
number = number + 1
until number > limit
Как и большинство императивных языков программирования, Lua предлагает инструкцию «for» в дополнение к циклу «while». Используются два варианта: C-подобный вариант с переменной цикла, а также вариант с итератором. Сначала рассмотрим использование инструкции «for» с переменной цикла:
start = 1
end = 10
for number = start, end do
print("Current number:", number) -- `1,2,3,4,5,6,7,8,9,10`
end
-- Explicitly set step to `2`
step = 2
for number = start, end, step do
print("Current number:", number) -- `1,3,5,7,9`
end
-- the step can also be negative
step = -2
-- With a negative step, swap start and end to count in descending order
for number = end, start, step do
print("Current number:", number) -- `10,8,6,4,2`
end
Удивительно, но переменная цикла, определенная в цикле «for», является локальной, а не глобальной, причем ее не нужно явно объявлять как локальную. Это имеет смысл, и в этом отношении Lua выгодно отличается от JavaScript. Там переменная цикла, объявленная без «let» или «var», является глобальной, что может привести к серьезным ошибкам.
Теперь мы можем перейти к циклу «for» Lua с итератором. В принципе, подход похож на Python. Вместо того чтобы увеличивать переменную цикла и использовать ее в качестве индекса в списке, мы выполняем итерацию непосредственно по элементам списка. Для создания итератора часто используется функция «ipairs()». Вот пример:
-- Define list of years
decades = {1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990}
-- Access the individual years using an iterator
for index, year in ipairs(decades) do
print(index, year)
end
Узнайте больше о функциях в Lua
Как и в C/C++, Java и JavaScript, функции определяются с помощью ключевого слова «function». Параметры функции записываются в круглых скобках после имен функций. Однако в Lua круглые скобки можно не указывать, если в качестве параметра функции используется только один литерал. Функция Lua не обязательно должна возвращать значение. Согласно определению, функция без значения — это «процедура»:
-- Define procedure
function hello(name)
print("Hello", name)
end
-- Call function
hello("good sir")
-- this is also possible
hello "good sir"
-- the following will not work, however
name = "Walter"
hello name -- syntax error
-- with a variable instead of a literal, the function must be called with parenthesis
hello(name)
Если вы хотите вернуть значение из функции, то ключевое слово «return» используется как обычно. Оно завершает выполнение функции и возвращает введенное значение. В следующем примере кода число возводится в квадрат:
-- Function with a single return value
function square(number)
-- the expression `number * number` is evaluated
-- and its value returned
return number * number
end
-- Square number
print(square(9)) -- `81`
Как и в Python и JavaScript, функция в Lua может принимать переменное количество параметров. Параметры хранятся в специальной конструкции «(…)». Для доступа к параметрам часто бывает полезно свести их в список с помощью выражения «{…}». В качестве альтернативы можно использовать функцию «select{}» для извлечения параметра под введенным индексом. Определить количество параметров можно с помощью выражения «#{…}».
-- Print all parameters of a function
function var_args(...)
for index, arg in ipairs({...}) do
print(index, arg)
end
end
var_args('Peter', 42, true)
Помимо переменного количества параметров, Lua также позволяет возвращать несколько значений с помощью инструкции «return». Это работает аналогично Python, но без явного типа «кортеж». Как и в Python, нормальным является присвоение нескольких переменных возвращаемому значению вызова функции. Вот пример:
-- Function with multiple return values
function first_and_last(list)
-- return first and last element of the list
individual return values are separated by a comma `,`
return list[1], list[#list]
end
people = {"Jim", "Jack", "John"}
-- Assignment of return values to multiple variables
first, last = first_and_last(people)
print("The first is", first)
print("The last is", last)
Если одно из возвращаемых значений не является обязательным, вы можете использовать знак подчеркивания (_) в качестве символа-заместителя, следуя общепринятым правилам, как показано в следующем примере:
function min_mean_max(...)
-- Set initial values for `min` and `max` to the first parameter
local min = select(1, ...)
local max = select(1, ...)
-- Initially set mean value to nil
local mean = 0
-- Iterate using the numbers
-- We do not need the index variable
-- and therefore use `_` as a placeholder
for _, number in ipairs({...}) do
-- Set a new minimum if necessary
if min > number then
min = number
end
-- Set a new maximum if necessary
if max < number then
max = number
end
-- Sum the numbers to find the average
mean = mean + number
end
-- Divide the numbers by their quantity
mean = mean / #{...}
return min, mean, max
end
-- Here we do not need the `mean` value
-- and therefore use `_` as a placeholder
min, _, max = min_man_max(78, 34, 91, 7, 28)
print("Minimum and maximum of the numbers are", min, max)
В Lua функции являются «гражданами первого класса». Другими словами, они могут быть связаны с переменными и, следовательно, могут также передаваться другим функциям в качестве параметров. Более того, функция может выступать в качестве возвращаемого значения функции. В целом, Lua позволяет осуществлять функциональное программирование, что показано здесь на примере хорошо известной функции «map()»:
-- `map()` function in Lua
-- Accepts a function `f` and a list as parameters
function map(f, list)
-- Create new list for output values
local _list = {}
-- Iterate using the elements of the list with an index
for index, value in ipairs(list) do
-- Apply function `f()` to the current value of the list
-- and save the return value in a new list on the same index
_list[index] = f(value)
end
-- Return new list
return _list
end
-- List of numbers
numbers = {3, 4, 5}
-- Function applied to all elements of the list
function square(number)
return number * number
end
-- Generate the squares via the `map()` function
squares = map(square, numbers) -- `{9, 16, 25}`
-- Output squared numbers
for _, number in ipairs(squares) do
print(number)
end
В функциональном программировании часто используется рекурсия. Функция вызывает себя многократно с измененными параметрами. Здесь нам необходимо проявить особую осторожность в Lua. Функции, к которым обращаются рекурсивно, должны быть явно объявлены как «локальные».
function f()
-- Recursive call
f() -- may refer to the global variable `f`
end
-- instead
local function f()
-- Recursive call
f() -- refers to the local function
end
-- equivalent to
local f; -- Declare variable `f` explicitly as `local`
f = function() -- Assignment of the function to the local variable `f`
f() -- is guaranteed to refer to the local function
end