Изучите Lua с помощью учебника по программированию Lua

Lua — это скриптовый язык, разработанный в Бразилии в начале 1990-х годов. Интерпретатор Lua переводит исходный текст программы Lua в байткод и затем выполняет ее. Сам интерпретатор написан на языке C, что обеспечивает большую производительность программ Lua во время выполнения. Более того, C-API позволяет встраивать код Lua в программы на C/C++. Lua — это мультипарадигмальный язык, подходящий для написания императивного, функционального и объектно-ориентированного кода.

Сильнейшим отличием Lua является простота встраивания в другие системы и языки. В результате Lua зарекомендовал себя как «язык-клея» и используется во многих игровых движках. Более того, этот язык можно использовать для управления веб-серверами, такими как Apache и nginx. Благодаря интерфейсу CGI, 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

Оцените статью
cdelat.ru
Добавить комментарий