Описание языка Lua
Введение
В качестве скриптового языка в Симплайт 5 используется язык программирования Lua версия 5.1.
Основные преимущества языка — простота и эффективность.
Lua представляет собой простой и компактный язык программирования. Он характеризуется небольшим количеством концепций, что упрощает процесс изучения и способствует сохранению компактности языка. Язык отличается высокой эффективностью реализации. Независимые тесты подтверждают, что Lua является одним из самых быстрых скриптовых языков.
С помощью скрипта в Симплайт 5 можно:
- Обрабатывать данные — реализовывать алгоритмы фильтрации, анализа и преобразования сигналов.
- Автоматизировать задачи — создавать сценарии для запуска процессов по расписанию или событию.
- Интегрироваться с внешними системами — взаимодействовать с базами данных, API или другими программами через Lua-библиотеки.
Ограничения движка
Неподдерживаемые функции:
Замечания: os.setenv(name, value) — позволяет установить переменную окружения. collectgarbage — не принимает аргументов и запускает сборщик мусора для всего приложения. file:setvbuf — не поддерживает буферизацию строки.
Синтаксис
Основным алфавитом языка является английский. Идентификаторы могут содержать буквы, цифры и символ подчеркивания, однако они не должны начинаться с цифры и не могут совпадать с ключевыми словами.
Замечание
Эти ограничения не распространяются на имена тегов внутри системы. Имена тегов в функцию передаются в виде строковых литералов.
Язык является регистрозависимым, то есть все ключевые слова должны быть написаны строчными буквами. Идентификаторы, которые отличаются только регистром букв, считаются различными.
Следующие 22 ключевых слова не могут быть использованы в качестве имён:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
Комментарии
Простой однострочный комментарий в Lua начинается с двойного минуса и продолжается до конца строки.
dim = { "one", "two", "three" } -- Строчный комментарий не обязан начинаться с начала строки,
-- он может следовать за другими языковыми конструкциями,
-- поясняя их.
--[[Многострочный комментарий начинается с идущих подряд за двумя минусами двух открывающихся квадратных скобок
и продолжается до двух подряд закрывающихся квадратных скобок. Как здесь: ]]
Замечание
Редактор скриптов не осуществляет обработку подсветки синтаксиса в многострочном комментарии. Вся область в двойных квадратных скобках подсвечивается стандартным образом, но при компиляции этот фрагмент кода обрабатывается как комментарий.
Типы данных
Lua — это язык программирования с динамической типизацией, в котором отсутствуют определения типов. Каждое значение в языке Lua имеет свой собственный тип:
nil(неопределенный) — отсутствие конкретного значения.boolean(логический) — содержит значения false (ложь) или true (истина).number(числовой) — представляет вещественные числа, т.е. числа двойной точности с плавающей точкой (типdoubleв языке C).string(строковый) — последовательность символов.function(функция) — объект, который содержит выполняемый код.userdata(пользовательские данные) — блок произвольной памяти, обычно используется для взаимодействия с кодом на языке C.thread(асинхронный поток) — независимый поток выполнения (сопрограмму).table(таблица) — ассоциативный массив.
Переменные
Глобальные переменные
Глобальная переменная доступна в любой части кода после своего создания. Любая переменная, объявленная без использования ключевого слова local, считается глобальной. Обращение к неинициализированной переменной не является ошибкой. В этом случае результатом будет значение nil:
Локальные переменные
Хороший стиль программирования заключается в применении локальных переменных везде, где это возможно. Локальные переменные помогают избежать засорения глобального окружения ненужными именами. Более того, доступ к локальной переменной быстрее, чем к глобальной.
Локальные переменные объявляются при помощи оператора local.
В отличие от глобальных переменных, область видимости локальной переменной ограничена блоком, где она была объявлена. Записывать локальные объявления можно везде, где можно записать оператор. Область видимости объявленных переменных начинается сразу после объявления и длится до конца блока.
Блок — это тело управляющей структуры, тело функции или кусок кода (файл или строка, где переменная была объявлена).
x = 10
local i = 1 -- локальная для куска
while i <= x do
local x = i*2 -- локальная для тела while
print(x) --> 2, 4, 6, 8,...
i = i + 1
end
if i > 20 then
local x -- локальная для тела if
x = 20
print(x + 2) -- (напечатает 22, если условие выполнится)
else
print(x) --> 10 (глобальная переменная)
end
print(x) --> 10 (глобальная переменная)
Операторы
Операторы сравнения
< > <= >= == ~= (последние два означают, соответственно, сравнение на равенство и на неравенство). Сравнения на равенство и неравенство могут быть применены к любым типам данных, в то время как остальные сравнения применимы только к строкам и числам.
Логические операторы
and or not — логические и или и не, соответственно, могут применяться к значениям любых типов и возвращают true либо false.
Все логические операции трактуют false и nil как ложные, а все остальные — как истинные значения. Операция and возвращает свой первый аргумент, если он ложный, иначе она возвращает свой второй аргумент. Операция or возвращает свой первый аргумент, если он не ложный; иначе она возвращает свой второй аргумент.
Операция not всегда возвращает булево значение.
Арифметические операторы
+ - * / - (унарный минус), % (остаток от деления), ^ (возведение в степень).
Примеры:
x^0.5 — возвращает квадратный корень из x
x^(-1/3) — значение, обратное кубическому корню из x
Для усечения x до трёх знаков после запятой достаточно взять выражение x = x % 0.001
Строки (string)
Строки в Lua могут содержать любые 8-битные символы, включая ноль ('\0'). Также они являются неизменяемыми значениями. Строковые литералы могут записываться в одинарных или двойных кавычках, служебные символы помещаются в них в стандартной для C-нотации с ведущим обратным слэшем. Многострочные литералы ограничиваются двумя подряд открывающимися и двумя подряд закрывающимися квадратными скобками.
Строки в Lua могут содержать следующие C-образные экранированные последовательности:
\а — звонок
\b — возврат на одну позицию (backspace)
\f — перевод страницы
\n — перевод строки
\r — возврат каретки
\t — горизонтальная табуляция
\v — вертикальная табуляция
\\ — обратный слеш
\" — двойная кавычка
\' — одинарная кавычка
Циклы
Оператор for имеет две разновидности:
- числовой.
- общий.
FOR числовой
Данный цикл будет выполнять определённые действия для каждого значения переменной var в диапазоне от exp1 до exp2 с шагом exp3. Третье выражение является необязательным: если оно отсутствует, то Lua считает значение шага равным 1.
FOR общий
Этот пример используетpairs, удобную итерирующую функцию для перебора таблицы, предоставляемую базовой библиотекой Lua. На каждом шаге этого цикла k получает ключ, a v получает значение, связанное с этим ключом.
ipairsитерирует только по числовым индексам таблицы, начиная с 1 и до первого пропущенного индекса. Перебирает элементы в порядке 1, 2, 3, ... и останавливается, когда встречает nil.
pairsитерирует по всем ключам таблицы (включая нечисловые и пропущенные индексы). Подходит для любых таблиц, включая словари (key-value). Возвращает пары key, value.
Таблицы (table)
Таблица — представляет собой ассоциативный массив.
Ассоциативный массив — это массив, который может быть индексирован не только числами, но и строками или любым другим значением языка, кроме nil.
Таблицы используются для представления обычных массивов, множеств, записей и других структур данных простым, однородным и эффективным способом. Каждая таблица может хранить значения с разными типами индексов и растет по мере добавления новых записей. Таблицу можно рассматривать как динамически выделяемый объект; программа работает только со ссылками (указателями) на них.
Таблица общего вида
empty = {} -- Пустая таблица
empty[1] = "первый" -- Добавление элемента с целым индексом
empty[3] = "второй" -- Добавление элемента с целым индексом
empty["третий"] = "третий" -- Добавление элемента со строковым индексом
empty[1] = nil -- Удаление элемента из таблицы
Классический массив
Строки индексируются по умолчанию целыми числами, начиная с 1:
Массив с произвольной индексацией
days2 = {[0]="воскресенье", [1]="понедельник", [2]="вторник", [3]="среда", [4]="четверг", [5]="пятница"}
Запись (структура)
Значения различных типов индексируются литералами:
person = {tabnum = 123342, -- Табельный номер
fio = "Иванов Степан Васильевич", -- Ф.И.О.
post = "слесарь-инструментальщик", -- Должность
salary = 25800.45, -- Оклад
sdate = "23.10.2013", -- Дата приёма на работу
bdate = "08.08.1973"} -- Дата рождения
pfio = person.fio -- Обращение к элементу структуры.
В Lua person.fio означает индексировать таблицу person, используя строку fio в качестве ключа.
Множество
Индексы используются для хранения значений:
workDays = {["понедельник"]=true, ["вторник"]=true, ["среда"]=true, ["четверг"]=true, ["пятница"]=true}
workDays["суббота"] = true -- Добавление субботы в число рабочих дней
workDays["среда"] = nil -- По средам больше не работаем
Замыкания
Lua поддерживает концепцию замыканий.
function makeaddfunc(x)
-- Возвращает новую анонимную функцию, которая добавляет x к аргументу
return function(y)
-- Когда ссылаемся на переменную x, которая вне текущей области,
-- и время жизни которой меньше, чем этой анонимной функции,
-- Lua создаёт замыкание
return x + y
end
end
plustwo = makeaddfunc(2) -- т.е. plustwo = function(y) return 2 + y end
print(plustwo(5)) -- Выводит 7
Каждый раз, когда вызывается makeaddfunc, создаётся новое замыкание для переменной x, так что каждая возвращаемая анонимная функция будет ссылаться на свой параметр x. Как и у любого другого объекта Lua, временем жизни замыкания управляет сборщик мусора.
Объектно-ориентированное программирование
В основе объектно-ориентированного программирования в Lua лежат таблицы.
Таблица в Lua представляет собой объект, который может иметь поля, названные с помощью идентификаторов. В этих полях могут храниться произвольные значения (свойства объекта), а также функции, которые определяют поведение объекта (методы объекта).
Синтаксический сахар, предоставляемый Lua, делает работу с объектами более привычной для программистов, имеющих опыт работы с традиционными объектно-ориентированными языками.
Синтаксический сахар — это способы написания кода, которые делают его более удобным и кратким для программиста, но не влияют на работу программы
В Lua отсутствует понятие класса, поэтому описывается отдельный объект, и все поля и методы относятся к нему. Свойства описываются аналогично элементам таблицы с ключами-идентификаторами, а методы — как поля-функции.
Описание методов включает явное указание в первом параметре так называемого "получателя" — параметра, который при вызове метода ссылается на объект, для которого он вызван. Помимо стандартного обращения к полю таблицы через точку, которое требует явного указания получателя в вызове метода, Lua поддерживает дополнительный синтаксис. Если в вызове или описании метода заголовок записывается в виде "Объект:метод", то получатель не указывается. При этом в теле метода он всё равно доступен под именем self.
-- Объект
Account = { -- Объект "счёт"
id, name, balance=0, -- свойства объекта: номер, название, баланс
credit = function (self, v) -- метод "расход" - описание внутри объекта с явным указанием получателя
if self.balance < v then error "Недостаточно денег на счёте" end
self.balance = self.balance - v
end
}
function Account:debet(v) -- метод "приход" - внешнее сокращённое описание (self не указывается)
self.balance = self.balance + v
end
Account.debet(Account, 10000) -- вызов метода - полный вариант
Account:credit(5000) -- вызов метода - сокращённый вариант
В языке Lua наследование, в том числе множественное, реализуется с использованием мета-таблиц и мета-методов. Эти же методы позволяют реализовать сокрытие данных и контроль доступа к полям таблицы-объекта.
По сравнению с другими языками программирования, где аналогичные функции реализованы с помощью специальных языковых конструкций, подход Lua может показаться более сложным и требующим более тщательного кодирования. Однако он обеспечивает большую гибкость и упрощает работу интерпретатора.