Скрипты на языке Lua
Написанный на Lua скрипт не имеет какой-либо специальной функции, с которой начиналось бы его выполнение. Скрипт можно рассматривать просто как набор команд (инструкций), который выполняется, начиная с первой инструкции.
Скрипт может быть как очень простым, состоящим всего из одной команды, так и весьма сложным, содержащим десятки, сотни и даже тысячи инструкций. Следующие друг за другом инструкции могут разделяться точкой с запятой (;). Однако это требование не является обязательным, поэтому весь приведённый ниже код является корректным с точки зрения синтаксиса:
a = 1; b = 2
a = 1 b = 2
a = 1;
b = 2;
a = 1
b = 2
Работа с переменными в Lua
Переменные используются для хранения значений в процессе выполнения скрипта.
Имена переменных в Lua
Именами (идентификаторами) переменных в Lua могут быть любые последовательности из букв, цифр и символа подчеркивания, начинающиеся не с цифры.
Обратите внимание
Язык Lua различает регистр символов, поэтому abc, Abc, ABC являются различными именами.
В таблице ниже приведены слова, которые зарезервированы языком Lua и не могут использоваться в именах переменных:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until
while
Кроме того, все имена, начинающиеся с символа подчеркивания, за которым идут заглавные буквы (например, _VERSION) также являются зарезервированными.
Какие переменные бывают в Lua?
Переменные в Lua могут быть глобальными и локальными. Если переменная не объявлена явно как локальная, она считается глобальной.
Глобальные переменные Lua
Глобальная переменная появляется в момент присваивания ей первого значения. До присваивания первого значения обращение к глобальной переменной даёт nil.
MsgBox(tostring (g)) --> nil
g = 1
MsgBox(tostring (g)) --> 1
Глобальная переменная существует до тех пор, пока существует среда исполнения скрипта и доступна любому Lua-коду, выполняемому в этой среде.
При необходимости удалить глобальную переменную можно явным образом, просто присвоив ей значение nil.
g = 1 — создаем глобальную переменную g со значением 1
...
g = nil — удаляем глобальную переменную g
MsgBox(tostring (g)) --> nil
Все глобальные переменные являются полями обычной таблицы, называемой глобальным окружением. Эта таблица доступна через глобальную переменную _G. Поскольку полями глобального окружения являются все глобальные переменные (включая саму _G), то _G._G == _G.
Локальные переменные Lua
Любые локальные переменные должны быть объявлены явно с использованием ключевого слова local. Объявить локальную переменную можно в любом месте скрипта. Объявление может включать в себя присваивание переменной начального значения. Если значение не присвоено, переменная содержит nil.
local a — объявляем локальную переменную a
local b = 1 — объявляем локальную переменную b, присваиваем ей значение 1
local c, d = 2, 3 — объявляем локальные переменные c и d, присваиваем им значения 2 и 3
Область видимости локальной переменной начинается после объявления и продолжается до конца блока.
Примечание
Областью видимости переменной называется участок кода программы, в пределах которого можно получить доступ к значению, хранящемуся в данной переменной.
Под блоком понимается:
тело управляющей конструкции (if-then, else, for, while, repeat);
тело функции;
фрагмент кода, заключённый в ключевые слова do...end.
Если локальная переменная определена вне какого-либо блока, её область видимости распространяется до конца скрипта.
a = 5 — глобальная переменная a
local i = 1 — переменная i локальна в пределах скрипта
while i <= a do — цикл от 1 до 5
local a = i^2 — переменная а локальна внутри цикла while
MsgBox(a) --> 1, 4, 9, 16, 25
i = i + 1
end
MsgBox(a) --> 5 (здесь обращение к глобальной a)
if i > 5 then
local a — переменная а локальна внутри then
a = 10
MsgBox(a) --> 10
else
MsgBox(a) --> 5 (здесь обращение к глобальной a)
end
do
local a = 20 — переменная а локальна внутри do-end
MsgBox(a) --> 20
end
MsgBox(a) --> 5 (здесь обращение к глобальной a)
Обратите внимание
Когда возможно, рекомендуется использовать локальные переменные вместо глобальных. Это позволит избежать «засорения» глобального пространства имён и обеспечит лучшую производительность (поскольку доступ к локальным переменным в Lua выполняется несколько быстрее, чем к глобальным).
Типы данных Lua
Какие типы данных поддерживает язык Lua?
Lua поддерживает следующие типы данных:
1. Nil (ничего). Соответствует отсутствию у переменной значения. Этот тип представлен единственным значением — nil.
2. Boolean (логический). К данному типу относятся значения false (ложь) и true (истина).
При выполнении логических операций значение nil рассматривается как false. Все остальные значения, включая число 0 и пустую строку, рассматриваются как true.
3. Number (числовой). Служит для представления числовых значений.
В числовых константах можно указывать необязательную дробную часть и необязательный десятичный порядок, задаваемый символами «e» или «E». Целочисленные числовые константы можно задавать в шестнадцатеричной системе, используя префикс 0x.
Примеры допустимых числовых констант: 3, 3.0, 3.1415926, 314.16e-2, 0xff.
4. String (строковый). Служит для представления строк.
Строковые значения задаются в виде последовательности символов, заключённой в одинарные или двойные кавычки:
a = «это строка»
b = 'это вторая строка'
Строки, заключённые в двойные кавычки, могут интерпретировать C-подобные управляющие последовательности (escape-последовательности), начинающиеся с символа «\» (обратный слэш):
\b (пробел),
\n (перевод строки),
\r (возврат каретки);
\t (горизонтальная табуляция),
\\ (обратный слеш);
\'' (двойная кавычка);
\' (одинарная кавычка).
Обратите внимание
Символ в строке также может быть представлен своим кодом с помощью escape-последовательности:
\ddd,
где ddd — последовательность из не более чем трёх цифр.
Кроме кавычек для определения строки могут также использоваться двойные квадратные скобки:
local a = [[Компания «Кронос»]]
Определение строки с помощью двойных квадратных скобок позволяет игнорировать все escape-последовательности, т. е. строка создаётся полностью так, как описана:
local a = [[string
string1
string2
string3
]] — «string
string1
string2
string3»
Примечание
При определении строки с помощью двойных квадратных скобок учитываются символы табуляции и переноса.
Двойные скобки могут быть вложенными. Для того чтобы их не перепутать, между скобками вставляется символ«равно» (=):
local a = [=[определение строки [[string]] в Lua]=]
— будет срока: «определение строки [[string]] в Lua»
5. Function (функция). Функции в Lua могут быть записаны в переменные, переданы как параметры в другие функции ивозвращены как результат выполнения функций.
6. Table (таблица). Таблица представляет собой набор пар «ключ» — «значение», которые называют полями илиэлементами таблицы. Как ключи, так и значения полей таблицы могут иметь любой тип, за исключением nil. Таблицы не имеют фиксированного размера: в любой момент времени в них можно добавить произвольное число элементов.
Подробнее — в статье «Создание таблиц в Lua»
7. Userdata (пользовательские данные). Является особым типом данных. Значения этого типа не могут быть созданы или изменены непосредственно в Lua-скрипте.
Userdata используется для представления новых типов, созданных в вызывающей скрипт программе или в библиотеках, написанных на языке С. Например, библиотеки расширений Lua для «CronosPRO» используют этот тип для представления таких объектов, как:
банки данных (класс Bank);
базы данных (класс Base);
записи (класс Record) и т. п.
8. Thread (поток). Соответствует потоку выполнения. Эти потоки никаким образом не связаны с операционной системой и поддерживаются исключительно средствами самого Lua.
Как в Lua задать тип переменной?
Lua не предусматривает явного задания типа переменной. Тип переменной устанавливается в момент присвоения переменной значения. Любой переменной может быть присвоено значение любого типа (вне зависимости от того, значение какого типа она содержала ранее).
a = 123 — переменная a имеет тип number
a = «123» — теперь переменная a имеет тип string
a = true — теперь переменная a имеет тип boolean
a = {} — теперь переменная a имеет тип table
Обратите внимание
Переменные типа table, function, thread и userdata не содержат самих данных, а хранят ссылки на соответствующие объекты. При присваивании, передачи в функцию в качестве аргумента и возвращении из функции в качестве результата копирования объектов не происходит, копируются только ссылки на них.
a = {} — создаем таблицу. В переменную a помещается ссылка на таблицу
b = a — переменная b ссылается на ту же таблицу, что и a
a[1] = 10 — элементу таблицы с индексом 1 присвоено значение 10
MsgBox(b[1]) --> '10'
b[1] = 20
MsgBox(a[1]) --> '20'
Остальные данные являются непосредственными значениями.
a = 10
b = a
a = 20
MsgBox(a) --> '20'
MsgBox(b) --> '10'
Как в Lua получить тип переменной?
Тип значения, сохранённого в переменной, можно выяснить при помощи стандартной функции type. Эта функция возвращает строку, содержащую название типа («nil», «number», «string», «boolean», «table», «function», «thread», «userdata»).
t = type («это строка») — t равно «string»
t = type (123) — t равно «number»
t = type (type) — t равно «function»
t = type (true) — t равно «boolean»
t = type (nil) — t равно «nil»
t = type (CroApp.GetBank()) — t равно «userdata»
Как в Lua преобразовать тип переменной?
Lua при необходимости автоматически преобразует числа в строки и наоборот. Например, если строковое значение является операндом в арифметической операции, оно преобразуется в число. Аналогично числовое значение, встретившееся в том месте, где ожидается строковое, будет преобразовано в строку.
a = «10» + 2 — a равно 12
a = «10» + 2 — a равно «10 + 2»
a = "-5.3e-10"*«2» — a равно -1.06e-09
a = «строка» + 2 — Ошибка! Невозможно преобразовать «строка» в число
Значение любого типа можно явным образом преобразовать в строку с помощью стандартной функции tostring.
a = tostring (10) — a равно «10»
a = tostring (true) — a равно «true»
a = tostring (nil) — a равно «nil»
a = tostring ({[1] = «это поле 1»}) — a равно «table: 06DB1058»
Из предыдущего примера видно, что содержимое таблиц функцией tostring не преобразуется. Выполнить такое преобразование можно с помощью функции render.
a = render (10) — a равно «10»
a = render (true) — a равно «true»
a = render (nil) — a равно «nil»
a = render ({[1] = «это поле 1»}) — a равно "{[1] = «это поле 1»}"
Для явного преобразования значения в число можно использовать стандартную функцию tonumber. Если значение является строкой, которую можно преобразовать в число (или уже является числом), функция возвращает результат преобразования, в противном случае возвращает nil.
a = tonumber («10») — a равно «10»
a = tonumber («10»..".5") — a равно 10.5
a = tonumber (true) — a равно «nil»
a = tonumber (nil) — a равно «nil»
Расстановка комментариев в Lua
Комментарий в Lua начинается двумя знаками «минус» (--) и продолжается до конца строки.
local a = 1 — однострочный комментарий
Если непосредственно после символов «--» идут две открывающие квадратные скобки ([[), комментарий являетсямногострочным и продолжается до двух закрывающих квадратных скобок (]]).
local a = 1 — [[ многострочный
комментарий ]]
Двойные скобки в комментариях могут быть вложенными. Для того чтобы их не перепутать, между скобками вставляется знак равенства (=):
local a = [[Компания «Кронос»]] — [=[
local a = [[Компания «Кронос»]]
]=]
Количество символов «=» определяет вложенность:
local a = [=[определение некоторой строки [[string]] в языке Lua]=] --[==[
local a = [=[определение некоторой строки [[string]] в языке Lua]=]
]==]
Операции, применяемые в Lua
В выражениях, написанных на Lua, могут применяться следующие виды операций:
1. Арифметические операции.
Lua поддерживает следующие арифметические операции:
+ (сложение);
— (вычитание);
* (умножение);
/ (деление);
^ (возведение в степень);
% (остаток от деления).
Обратите внимание
Арифметические операции применимы как к числам, так и к строкам, которые в этом случае преобразуются в числа.
2. Операции сравнения.
В Lua допустимы следующие операции сравнения величин:
== (равно);
~= (не равно);
< (меньше);
> (больше);
<= (меньше или равно);
>= (больше или равно).
Обратите внимание
Операции сравнения всегда возвращают логическое значение true или false.
Правила преобразования чисел в строки (и наоборот) при сравнениях не работают, т. е. выражение «0» == 0 даёт в результате false.
3. Логические операции.
К логическим операциям относятся:
and (логическое И).
Операция and возвращает свой первый операнд, если он имеет значение false или nil. В противном случае, операция возвращает второй операнд (причём этот операнд может быть произвольного типа).
a = (nil and 5) — a равно nil
a == (false and 5) — a равно false
a == (4 and 5) — a равно 5
or (логическое ИЛИ).
Операция or возвращает первый операнд, если он не false и не nil, иначе он возвращает второй операнд.
a == (4 or 5) — a равно 4
a == (false or 5) — a равно 5
Обратите внимание
Логические операции and и or могут возвращать значения любых типов.
Логические операции and и or вычисляют значение второго операнда только в том случае, если его нужно вернуть. Если этого не требуется, второй операнд не вычисляется. Например:
a == (4 or f()) — вызова функции f() не произойдет
not (логическое НЕ).
Операция not всегда возвращает true или false.
4. Операция конкатенации.
Для конкатенации (объединения) строк служит операция… (две точки).
a = «Кронос».."-"..«Информ» — переменная a получит значение «Кронос-Информ»
Обратите внимание
Если один или оба операнда являются числами, выполняется их преобразование в строки.
a = 0..1 — переменная a получит значение «01»
5. Операция получения длины.
В Lua определена операция длины #, которую можно использовать для получения длины строки.
a = «строка»
len = #a — len равно 6
len = #«ещё строка» — len равно 10
Обратите внимание
С помощью операции # можно также узнать максимальный индекс (или размер) массива. Подробнее — в статье «Работа с массивами в Lua» .
Приоритет операций в Lua
В языке Lua выполнение операций осуществляется в соответствии со следующим приоритетом (в порядке убывания):
1. ^
2. not # — (унарный)
3. * / %
4. + -
5. ..
6. < > <= >= ~= ==
7. and
8. or
Вызов скриптов из форм
С каждой формой (включая вложенные формы) связан отдельный скрипт, который обычно содержит функции, выполняющие обработку событий формы и её элементов.
Когда форма запускается, её скрипт загружается в глобальное окружение. При возникновении события формы или её элемента система вызывает сопоставленную этому событию функцию-обработчик.
Необходимо отметить, что скрипт формы, хотя и не содержит вызова функции module, фактически является модулем. Это означает, что переменные, объявленные в скрипте формы без ключевого слова local, не выносятся в глобальное окружение и доступны только внутри этого скрипта. Если необходимо сделать какое-либо значение доступным для скриптов других форм, его следует явным образом определить в глобальной таблице _G:
_G.var = 123
Другой скрипт форм сможет прочитать это значение следующим образом:
local a = _G.var
Блоки операторов (инструкций)
К основным операторам Lua относятся:
присваивание;
условный оператор;
операторы для организации циклов.
Группа операторов может быть объединена в блок (составной оператор) при помощи конструкции do… end.
do — начало блока
<оператор1> — тело блока
<оператор2>
...
<операторN>
end — конец блока
Блок открывает новую область видимости, в которой можно определять локальные переменные.
a = 5 — глобальная переменная a
do
local a = 20 — внутри do-end определяется локальная переменная а
MsgBox(a) --> 20
end
MsgBox(a) --> 5 (здесь обращение уже к глобальной a)
Оператор присваивания в Lua
Присваивание изменяет значение переменной или поля таблицы. В простейшем виде присваивание может выглядеть так:
a = 1 — переменной a присвоено значение 1
a = b + c — переменной a присвоена сумма значений переменных b и с
a = f(x) — переменной a присвоено значение, возвращённое функцией f(x)
В Lua допускается так называемое множественное присваивание, когда несколько переменных, находящихся слева от оператора присваивания, получают значения нескольких выражений, записанных справа от оператора присваивания:
a, b = 1, 5*c — a равно 1; b равно 5*c
Если переменных больше чем значений, «лишним» переменным присваивается nil.
a, b, c = 1, 2 — a равно 1; b равно 2; c равно nil
Если значений больше чем переменных, «лишние» значения игнорируются.
a, b = 1, 2, 3 — a равно 1; b равно 2; значение 3 не использовано
Множественное присваивание можно использовать для обмена значениями между переменными:
a = 10; b = 20 — a равно 10, b равно 20
a, b = b, a — теперь a равно 20, b равно 10
Условный оператор (if) в Lua
Оператор if проверяет истинность заданного условия. Если условие является истинным, выполняется часть кода, следующая за ключевым словом then (секция then). В противном случае, выполняется код, следующий за ключевым словом else (секция else).
if a > b then
return a — если a больше b, вернуть a
else
return b — в противном случае — вернуть b
end
Секция else является необязательной.
if a < 0 then
a = 0 — если a меньше 0, присвоить a значение 0
end
Вместо вложенных операторов if можно использовать конструкцию elseif. Например, приведенный код:
if a == 1 then
return «Иван» — если a равно 1
else
if a == 2 then
return «Петр» — если a равно 2
else
if a == 3 then
return «Сергей» — если a равно 3
else
return «Нет такого игрока» — если a — ни одно из перечисленных
end
end
end
будет проще для восприятия, если заменить его следующим:
if a == 1 then
return «Иван» — если a равно 1
elseif a == 2 then
return «Петр» — если a равно 2
elseif a == 3 then
return «Сергей» — если a равно 3
else
return «Нет такого игрока» — если a — ни одно из перечисленных
end
Цикл с предусловием (while) в Lua
Оператор while предназначен для организации циклов с предусловием и имеет следующий вид:
while <condition> do
… — тело цикла
end
Перед каждой итерацией цикла проверяется условие <condition>:
если условие ложно, цикл завершается и управление передаётся первому оператору, следующему за оператором while;
если условие истинно, выполняется тело цикла, после чего все действия повторяются.
i = 10; t = {}
while i > 0 do — цикл от 10 до 1
t[i] = «поле »..i
i = i — 1
end
Для выхода из цикла до его завершения можно использовать оператор break.
a = {3, 5, 8, -6, 5}
i = #a
while i > 0 do — ищем в массиве отрицательное значение
if a[i] < 0 then break end — если найдено, прерываем цикл
i = i — 1 — иначе переходим к следующему элементу
end
if i > 0 then
MsgBox («Индекс отрицательного значения: »..i)
else
MsgBox («Массив не содержит отрицательных значений»)
end
Примечание
Подробнее об особенностях использования оператора break — в статье «Операторы break и return»
Цикл с постусловием (repeat) в Lua
Оператор repeat предназначен для организации циклов с постусловием и имеет следующий вид:
repeat
… — тело цикла
until <condition>
Тело цикла выполняется до тех пор, пока условие <condition> не станет истинным. Проверка условия осуществляется после выполнения тела цикла, поэтому в любом случае тело цикла выполнится хотя бы один раз.
— суммируем значения массива a, пока сумма не превысит 10
a = {3, 2, 5, 7, 9}
i = 0; sum = 0
repeat
i = i + 1
sum = sum + a[i]
until sum > 10
MsgBox («Сложено »..i.." элементов. Сумма равна "..sum)
Для выхода из цикла до его завершения можно использовать оператор break.
Примечание
Подробнее об особенностях использования оператора break — в статье «Операторы break и return»
Циклы с оператором for в Lua
Оператор for предназначен для организации циклов и допускает две формы записи:
простую (числовой for);
расширенную (универсальный for).
Простая форма оператора for
Простая форма оператора for имеет следующий вид:
for var = exp1, exp2, exp3 do
… — тело цикла
end
Тело цикла выполняется для каждого значения переменной цикла (счётчика) var в интервале от exp1 до exp2, с шагом exp3.
Примечание
Шаг может не задаваться. В этом случае он принимается равным 1.
for i = 1, 10 do — цикл от 1 до 10 с шагом 1
MsgBox («i равно »..i)
end
for i = 10, 1, -1 do — цикл от 10 до 1 с шагом -1
MsgBox («i равно »..i)
end
Обратите внимание
Выражения exp1, exp2 и exp3 вычисляются всего один раз, перед началом цикла. Так, в примере ниже, функция f(x) будет вызвана для вычисления верхнего предела цикла только один раз:
for i = 1, f(x) do — цикл от 1 до значения, возвращенного функцией f()
MsgBox («i равно »..i)
end
Переменная цикла является локальной для оператора цикла и по его окончании не определена.
for i = 1, 10 do — цикл от 1 до значения, возвращенного функцией f()
MsgBox («i равно »..i)
end
MsgBox («После выхода из цикла i равно »..i) — Неверно! i равно nil
Обратите внимание
Значение переменной цикла нельзя изменять внутри цикла: последствия такого изменения непредсказуемы.
Для выхода из цикла до его завершения используется оператор break.
a = {3, 5, 8, -6, 5}
for i = 1,#a do — ищем в массиве отрицательное значение
if a[i] < 0 then — если найдено...
index = i — сохраняем индекс найденного значения...
break — и прерываем цикл
end
end
MsgBox («Индекс отрицательного значения: »..index)
Примечание
Подробнее об особенностях использования оператора break — в статье «Операторы break и return» )
нужен.