Введение в язык Lua¶
Содержание
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)
, который удаляет элемент в таблице по указанному индексу, перестраивая при этом индексы.
Примечание
Если таблица содержит ключи не с целочисленным индексом, то индекс вставленного элемента будет целым числом равным последнему целочисленному индексу + 1
Важно
Индексы в языке Lua начинаются с 1, а не с 0 как в других языках программирования
Получить размер таблицы можно с помощью оператора #
:
print(#tbl)
Важно
Размер таблицы определяется верно если все ее индексы целочисленные и последовательные, т.е. нет дыр. К примеру, если мы вручную удалим элемент из таблицы
следующим образом 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
Примечание
Элементы, которые возвращает функция 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)
.