Введение в язык Lua¶
Contents
Lua - скриптовый язык программирования с динамической типизацией и автоматическим управлением памятью, отличающийся простотой дизайна и легкостью обучения. Благодаря своей простоте и встраиваемости, используется во многих играх и приложениях. Также язык прекрасно подходит для непрофессиональных программистов из-за простого синтаксиса. Имеет эффективные средства для взаимодействия с языком C, что позволяет совместить мощь языка C и простоту языка Lua. Язык поддерживает небольшое количество встроенных типов данных, а комбинированные типы данных представлены одной структурой - таблицей.
Типы данных¶
| Тип | Описание |
|---|---|
nil |
Обозначает отсутствие значения |
boolean |
Логический тип данных. Возможные значения: true (истина), false (ложь) |
number |
Числовой тип данных, соответствует типу данных double (вещественные числа) в других языках. Пример: 3.5, 12 |
string |
Строковый тип данных(массив символов). Пример: "Hello world" |
function |
Функция. В Lua - полноправный объект(функцию можно передавать как параметр, возвращать и т.д.) |
userdata |
Пользовательские данные, полученные обычно из кода на другом языке(С/С++) |
table |
Основная комбинированная структура данных языка Lua. Пример: tbl = {"Hello world", 2} |
Переменные¶
Переменная это имя для значения в памяти, которое может быть любого типа. Переменные могут быть глобальные и локальные. При создании
переменной она по умолчанию является глобальной, если не указано ключевое слово local перед ее именем:
x = 50 -- глобальная переменная
local var1, var2 = 10, 20 --локальные переменные(множественное присваивание)
Локальные переменные ограничены областью видимости блока(это может быть тело цикла, функции или модуля), в котором они объявлены.
Операторы¶
Оператор это символ, благодаря которому совершается манипуляция над операндами.
Арифметические операторы¶
Для примера предположим, что имеется несколько переменных: a=10 b=30 c=25
| Оператор | Описание | Пример |
|---|---|---|
+ |
Сложение. | a + b = 40 |
- |
Вычитание. | a - b = -20 |
* |
Умножение. | a * b = 300 |
/ |
Деление. | b / a = 3 |
% |
Модуль(остаток от целочисленного деления). | c % a = 5 --(c = 2*a + 5) |
^ |
Экспонента. | a ^ 2 = 100 |
- |
Унарный минус. | -a = -10 |
Операторы сравнения¶
Для примера предположим, что имеются две переменные: a=10 b=30
| Оператор | Описание | Пример |
|---|---|---|
== |
Сравнение двух операндов на равенство. | a == b --> false |
~= |
Сравнение двух операндов на неравенство. | a ~= b --> true |
> |
Сравнение двух операндов на больше. | a > b --> false |
< |
Сравнение двух операндов на меньше. | a < b --> true |
>= |
Сравнение двух операндов на больше или равно. | a >= b --> false |
<= |
Сравнение двух операндов на меньше или равно. | a <= b --> true |
Логические операторы¶
Логические операторы, как и контролирующие структуры считают nil и false как false (ложь), а все остальное как true (истина).
Для примера предположим, что имеются переменные: a=true b=false с=nil
| Оператор | Описание | Пример |
|---|---|---|
and |
Логическое “И”. Если первый операнд false, то возвращает его. В противном случае возвращает второй операнд. |
|
or |
Логическое “Или”. Если первый операнд true, то возвращает его. В противном случае возвращает второй операнд. |
|
not |
Логическое “Нет”. Если операнд true, то возвращает false, и наоборот |
|
Остальные операторы¶
Также поддерживаются еще два оператора: конкатенации и длины
| Оператор | Описание | Пример |
|---|---|---|
.. |
Конкатенация(сложение) двух строк | "Hello world" .. "!" --> "Hello world!" |
# |
Длина строки или кол-во элементов в таблице | #"Hello" --> 5 |
Контролирующие структуры¶
Циклы¶
Циклы необходимы, когда нужно выполнить инструкцию или группу инструкций некоторое количество раз. Циклы в Lua бывают разных типов:
| Цикл | Описание | Пример |
|---|---|---|
while |
Выполняет инструкции пока заданное условие является истинным. Перед выполнением проверяет условие на истинность. | condition = true
while condition do
condition = someFunc()
end
|
Числовой for |
Обладает следующим синтаксисом: for var=exp1,exp2,exp3 do ... end, где exp1 - начальное значение, exp2 - конечное значение, exp3 - шаг.
exp3 является необязательным(по умолчанию равно 1) |
for i=1, 10 do print(i) end
for i=20, 5, -1 do print(i) end
|
Общий for |
Позволяет пройтись по элементам, полученным от итерирующей функции(например, ipairs). | tbl = {1, 3, 5, 7, 9}
for element in ipairs(tbl) do
print(element)
end
|
repeat |
Выполняет инструкции пока заданное условие является истинным. Проверяет условие на истинность после выполнения(т.е. выполнится как минимум один раз). | repeat
condition = someFunc()
until condition
|
Также циклы могут быть вложены друг в друга:
for i=1,3 do
for j=10,20 do
print(j)
end
end
Инструкции break и return могут быть использованы для прерывания цикла. break прерывает цикл, в то время как return сразу же возвращает значение функции и завершает ее:
for i=0,10 do
if i == 6 then
print(i)
break
end
end
Условия¶
Инструкция if проверяет условие на истину, и выполняет последующие инструкции в случае истины. В случае неуспешной проверки(условие ложно), выполняется else
часть(если она присутствует). Если необходимо несколько else условий то их удобнее заменить elseif инструкциями, без необходимости закрывать каждую инструкцию с помощью end:
if a > 0 then print("Positive") end
if b > 0 then
print("Positive")
elseif b < 0 then
print("Negative")
elseif b == 0 then
print("Zero")
else
print("Not a number")
end
Также условия могут быть вложены друг в друга:
if a > 0 then
if b > 0 then
someFunc()
else
otherFunc()
end
else
a = b
end
Функции¶
Функция это группа инструкций, которые выполняют какую-либо задачу. В Lua есть некоторое количество встроенных функций(например, print). Можно
написать свою функцию, объявив ее следующим способом:
local function functionName(arg1, arg2, arg3, ..., argn)
value = ...
...
return value
end
local - необязательная часть(функция будет локальной в случае такого объявления, т.е. доступной в рамках блока, в котором она объявлена).
functionName - имя нашей функции.
arg1, arg2, arg3, ..., argn - аргументы функции, перечисленные через запятую
... - тело нашей функции, которое содержит все инструкции, которые необходимо выполнить.
return value - значение, которое функция возвращает. Является необязательным: если не указано, то подразумевается, что функция возвращает nil.
end - конец блока функции.
Для примера напишем функцию, которая складывает два числа:
function addNumbers(a, b)
return a + b
end
print(addNumbers(1,3)) --> 4
Еще пример - нахождение максимума из двух чисел:
function max(num1, num2)
return num1 > num2 and num1 or num2 -- если num1 больше, то условие true и возвращается num1, в противном случае num2
end
print(max(1,5)) --> 5
Функция может принимать переменное количество аргументов, для этого укажите “…” в качестве аргумента функции. Напишем функцию, которая ищет максимум переменного количества чисел:
function max(...)
local args = {...} -- массив аргументов
if #args == 0 then return end -- если нет аргументов, то не выполняем инструкции ниже
local result = args[1] -- максимум инициализируем первым элементом массива
for i, num in ipairs(args) do
if num > result then
result = num
end
end
return result
end
print(max(1,15,2,5,6,24,12)) --> 24
Также функция может возвращать несколько значений:
function findByCondition(array, condition)
for idx, value in ipairs(array) do
if condition(value) then
return idx, value
end
end
end
local idx, value = findByCondition({1, -5, 12}, function(value) return value > 10 end) -- передаем функцию в качестве параметра
print("Value ", value, " found at index ", idx)
Таблицы¶
Таблица это составной объект, который представляет собой множество пар “ключ-значение”. Ключами могут быть значения любых типов, кроме nil. Значения могут
быть представлены любым типом, в том числе nil (что равносильно удалению пары из таблицы). Таблицы - очень гибкий и мощный инструмент языка, т.к. с их помощью можно
создать любой пользовательский тип данных, будь то массив, структура, множество и т.д:
myTable = {} -- инициализация пустой таблицы
myTable[1] = "Hello " -- элемент с целым индексом
myTable[2] = "world"
myTable["third"] = "!" -- элемент со строковым индексом
myTable[1] = nil -- удаление элемента из таблицы
otherTable = {"First", "Second", "Third"} -- инициализация таблицы с элементами
otherTable[4] = "Fourth"
pet = {
name = "cat",
weight = 5
} -- структура
print(pet.name) --> cat (обращение к элементу структуры)
Существует несколько полезных методов для работы с таблицами. Первый это table.insert(tbl, pos, el), который в качестве параметров принимает таблицу,
позицию для вставки(опционально) и элемент, который необходимо вставить. Если позиция не указана, то элемент будет вставлен в конец. Второй
это table.remove(tbl, pos), который удаляет элемент в таблице по указанному индексу, перестраивая при этом индексы.
Note
Если таблица содержит ключи не с целочисленным индексом, то индекс вставленного элемента будет целым числом равным последнему целочисленному индексу + 1
Important
Индексы в языке Lua начинаются с 1, а не с 0 как в других языках программирования
Получить размер таблицы можно с помощью оператора #:
print(#tbl)
Important
Размер таблицы определяется верно если все ее индексы целочисленные и последовательные, т.е. нет дыр. К примеру, если мы вручную удалим элемент из таблицы
следующим образом tbl[2] = nil, то размер будет считаться неверно. Также размер будет считаться неверно, если в таблице присутствуют элементы не с
целочисленными индексами, а, например, со строковыми. Получить размер такой таблицы можно, только пройдя по всем ее элементам циклом for с помощью итерирующей
функции pairs
Итерирующие функции¶
Чтобы пройтись по всем элементам таблицы нужно использовать одну из итерирующих функций: pairs и ipairs. Первая используется, если таблица содержит нецелочисленные
индексы. Вторая используется, если индексы таблицы целочисленны и последовательны:
tbl = {}
tbl["pet"] = "dog"
tbl["age"] = 4
for k, v in pairs(tbl) do
print(k, " ", v) --> "pet dog", "age 4"
tbl = {}
table.insert(tbl, 1)
table.insert(tbl, 2)
table.insert(tbl, 3)
for k, v in ipairs(tbl) do
print(k, " ", v) --> "1 1", "2 2", "3 3"
end
Note
Элементы, которые возвращает функция ipairs последовательны, т.е. начинаются с индекса 1, затем идет 2 и т.д. Функция pairs возвращает же элементы
в произвольном порядке. Также если в таблице с целочисленными индексами имеются дыры(пропуск некоторых индексов), то функция ipairs вернет элементы
с индексами до первой такой дыры, а последующие пропустит.
Объекты¶
Lua не поддерживает объектно-ориентированное программирование, как многие другие языки, однако таблицы могут хранить любые значения, в том числе функции. Таким образом мы можем создавать объекты, тем самым объединив данные и методы, которые с ними работают:
local tree = {
height = 0,
grow = function(self) self.height = self.height + 1 end,
show = function(self) print(self.height) end
}
tree:grow()
tree:show() --> 1
tree:grow()
tree:show() --> 2
В данном примере self это переменная, указывающая на сам объект, а синтаксис с : позволяет передать этот объект первым параметром в функцию,
иначе бы пришлось использовать следующий синтаксис: tree.show(tree).