в lua что значит
Про Lua
Введение
Типы данных
Область видимости переменных
Функции
Итак, мы выяснили, что функция является типом данных. То есть, функции можно возвращать из функций.
Пример:
Функции могут возвращать несколько значений.
Пример:
Переменная _ используется в Lua для замены ненужной переменной.
Например, из функции f() нам нужно получить только третий параметр:
«Замороженные» переменные (upvalues)
Функция может обращаться к локальным переменным, которые определены вне ее. Если при вызове функции локальная переменная уже вышла из области видимости и была разрушена, то функция пользуется тем значением внешней локальной переменной (external local variable), которое было на момент определения функции.
Пример:
Изменим время жизни локальной переменной x:
Функции, кстати, тоже могут быть локальными:
Некоторые особенности при вызове функций
Например, есть две функции:
function f1()
return 1, 2
end
function f2(x, y)
return x + y
end
Поскольку первая функция возвращает два значения, а вторая принимает два значения, то функции могут быть вызваны так:
function f1()
return 1, 2, 3
end
function f2(x, y, z)
return x + y + z
end
Понятно, что f1 дополняет последние параметры f2 нужным числом своих параметров. Однако это работает, только если вызов f1 стоит последним в списке параметров. Что будет если вызвать функции так:
В этом случае из f1 будет взят только первый параметр. А если так:
Да, третьим параметром будет nil, что при выполнении математической операции сгенерирует ошибку.
Переменное число параметров
В Lua, как и в С, в функцию можно передавать переменное число параметров. Синтаксис также похож:
Таблицы
Заполним ее различными типами данных:
t[1] = 10
t[«Вася»] = «осел»
t[3] = true
local function f()
return 1
end
Таблица может быть проинициализирована при создании:
Массивы
Если при инициализации таблицы ключи не были указаны, то Lua сама присваивает значениям ключи, начиная с 1.
Внимание! Индексация массивов в Lua начинается с 1, не с 0!
Получение размера массива выполняется оператором #:
Оператор # возвращает целое число n, такое, что t[n] не nil, и t[n + 1] равно nil. Другими словами оператор #, возвращает максимальный индекс непрерывной последовательности ключей от начала массива. Соответственно, для таблицы:
Для массива, в котором значения хранятся одно за другим, оператор # вернет количество элементов в массиве.
Обход элементов таблицы
local t = <1, 2, 3, "Вася">
for i = 1, #t, 1 do
print(t[i])
end
Обычные таблицы обходятся циклом for с итератором:
local t = <1, 2, x = 4, y = 5, ["Вася"] = "осел">
for key, value in pairs(t) do
print(key, value)
end
— > 1 1
— > 2 2
— > y 5
— > x 4
— > Вася осел
Как видно из печати, порядок элементов в таблице отличается от порядка, в котором значения помещали в таблицу, поскольку внутри хэш-таблицы ключи сортируются по некоему признаку.
Методы
Рассмотрим следующую конструкцию (попытка сымитировать ООП):
function t:fun()
print(self.x)
end
t:fun()
На что все это похоже? Это похоже на ООП. Есть, объект, есть метод объекта, есть вызов метода объекта. Чего нет? Нет возможности создавать объекты определенного типа (например типа t). То есть и объект, и метод существуют в единственном экземпляре. Для того, чтобы создать объект типа tt, который ведет себя так же, как объект типа t, нам придется повторить всю процедуру с самого начала:
function tt:fun()
print(self.x)
end
function checkMetod(x)
x:fun()
end
Есть ли выход из сложившейся ситуации? Да, есть. Но о нем мы поговорим после того, как рассмотрим метатаблицы.
Метатаблицы.
Метатаблицы позволяют переопределить поведение встроенных типов. Для таблиц это можно сделать прямо в Lua, а для других типов придется это делать через С.
Метатаблицы схожи с конструкцией operator() в C++. Рассмотрим, например, как можно складывать две таблицы (в самом языке такая операция не предусмотрена).
С помощью метатаблиц можно реализовать некое подобие объектно-ориентированного программирования.
Попробуем это сделать. Сначала создадим базовый класс (обычная таблица):
В ней создадим поле field :
и две функции для работы с этим полем:
function Base:setField(value)
self.field = value
end
function Base:getField()
return self.field
end
Как видно, пока это обычная таблица. Установим у этой таблицы новую метатаблицу.
Изменим значение этого поля:
function Child:getField()
return ‘zzz’
end
Создадим объект типа Child :
А как же быть, если мы хотим вызвать для Child метод родительского класса? А очень просто:
Модули
Module1.var1 = 1
function Module1.fun1(a, b)
return a + b + Module1.var1
end
аналогично файл module2.lua:
dofile(‘modules.lua’)
dofile(‘module1.lua’)
dofile(‘module2.lua’)
Загрузка модулей
то для загрузки модуля foo Lua будет пытаться открыть следующие файлы (порядок поиска совпадает с порядком задания шаблонов):
то загрузчик будет пытаться открыть следующие файлы (порядок сохранен):
ООП на модулях
В С++ это довольно привычно, располагать каждый класс в отдельном файле (обычно в двух, ИмяКласса.h и ИмяКласса.cpp). В Lua, поверьте, это тоже удобно :).
Проект удобно организовать следующим образом:
.
..
— папка
— папка
start.lua
.
Пути к Lua-библиотекам и С-библиотекам (загрузчики) можно прописать двумя различными способами.
Первый способ:
В первых двух строчках файла start.lua написать:
Второй путь:
Использовать системные переменные.
Создать файл start.bat в котором написать следующее:
set LUA_PATH=.\luamodules\?.lua;
set LUA_CPATH=.\cmodules?.dll
lua.exe start.lua
а в самом файле start.lua уже ничего не писать.
function setBaseClass(class, baseClass)
base.assert(baseClass.mtab)
base.setmetatable(class, baseClass.mtab)
end
В начале файла мы видим магическую строку
local Factory = base.require(‘Factory’)
function new()
return Factory.create(_M)
end
function construct(self)
base.print(‘Base created!’)
self.field = ‘text’
end
Проясним некоторые места:
local Factory = base.require(‘Factory’)
Для работы нам будет нужен модуль Factory.
Внимание!
Для избежания ошибок с циклическими зависимостями модулей, все функции require нужно вызывать после выполнения функции module!
function new()
return Factory.create(_M)
end
Для удобства. Конечно, в прикладном коде можно вызвать и
local base = Factory.create(Base)
но мне кажется что вызов
local base = Base.new()
короче и очевидней.
function construct(self)
base.print(‘Base created!’)
end
local base = Base.new()
print(base:getField())
base:setField(1)
print(base:getField())
Запускаем его на выполнение.
Base created!
text
1
local Factory = base.require(‘Factory’)
local Base = base.require(‘Base’)
local child = Child.new(1, 2)
print(child:getField())
child:setField(1)
print(child:getField())
Запускаем его на выполнение.
Base created!
text
1
Base created!
Child created! 1 2
zzz
zzz
Завершающие штрихи. Как создасть статический член класса? Очень просто. Внутри модуля объявить его либо как
либо (предпочтительнее, поскольку более очевидно чего вы хотите)
Соответственно, статический метод класса будет без первого параметра self:
function staticFun(param1, param2)
end
Файлы проекта можно скачать здесь.
Уф, жаркая была битва! Еще о чем-нибудь интересненьком в другой раз.
Пишите письма!
Как написать Lua скрипты и где они используются? Подробный обзор
Lua-скрипты пишутся на языке программирования Lua, что очень даже естественно. Lua — это интерпретируемый скриптовой язык родом из Бразилии. Год его рождения — 1993-й год. С тех пор он постоянно развивается и расширяет свои возможности. Lua — это язык свободного распространения. По своей функциональности он ближе к JavaScript, но по некоторым компетентным мнениям он более гибкий, чем JS.
Скрипты Lua
Скрипты Lua не имеют собственной функции, с которой бы начиналось их выполнение. Это просто список заданных инструкций, которы е выполняются по порядку, стартуя с первой.
Скрипты Луа могут быть:
Переменные в скриптах Lua
Есть 4 требования при наименовании переменных:
Все переменные, как и в любом другом языке, делятся на 2 основных типа и могут быть:
Какую типизацию данных воспринимают скрипты Луа
Сам по себе язык Lua воспринимает следующую типизацию данных:
Любая переменная готова использовать любой из перечисленных типов — это определяет динамическая типизация языка Lua.
Комментарии в скриптах Lua
Комментарии в скриптах Lua могут быть:
Где используются скрипты Lua
Скриптинг Lua не так распространен, как JavaScript, но все равно за долгие годы существования этого языка он нашел последователей и занял свое место. Скрипты Lua применяются в проектах из разных сфер, некоторые из них довольно известные. Например:
Заключение
Отметим несколько достоинств скриптов Луа:
Да, Lua не самый популярный язык программирования, но он однозначно достоин внимания.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
Lua (язык программирования)
Парадигма | мультипарадигмальный: императивный, функциональный, прототипно-ориентированный, скриптовый, встраиваемый |
---|---|
Спроектировано | Роберту Иерузалимски, Валдемар Селиш, Луиш Энрике ди Фигейреду |
Первый появившийся | 1993 |
Печать дисциплины | динамическая, строгая, «утиная» |
Расширение файла | .lua |
Главная реализация | |
Lua, LuaJIT, LLVM-Lua, LuaCLR, Nua, Lua Alchemy | |
Диалект | |
MetaLua | |
Под влиянием | |
Scheme, Снобол, Модула, Клу, C++ | |
Влияние | |
Io, GameMonkey, Squirrel, Dao, MiniD |
По идеологии, возможностям и реализации язык ближе всего к JavaScript, но Lua имеет более мощные и гораздо более гибкие конструкции. Механизмы объектно-ориентированного программирования, включая множественное наследование, могут быть реализованы с использованием метатаблиц, но понятие классов не содержится в Lua. Реализуемая объектная модель может быть названа прототипной (как в JavaScript). Использование языка в основном происходит для создания тиражируемого программного обеспечения. По причине легкого встраивания, скорости работы и легкости обучения язык получил признание среди пользователей, которым требуется язык программирования уровней и расширений во многих играх. Lua является свободным программным обеспечением с открытым исходным кодом, распространяется под лицензией MIT.
Содержание
История создания
Lua разработана подразделением Tecgraf (группа технологий компьютерной графики) Католического университета Рио-де-Жанейро в Бразилии. Язык используется с 1993 года. Авторы языка — Роберту Иерузалимски, Луиш Энрике ди Фигейреду (Luiz Henrique de Figueiredo) и Валдемар Селиш (Waldemar Celes).
Родителями Lua были языки конфигурирования и описания данных SOL (Simple Object Language) и DEL (Data-Entry Language). Они были независимо разработаны в Tecgraf в 1992—1993 годах для добавления некоторой гибкости в два отдельных проекта. Из-за недостатков в SOL и DEL(отсутствовали управляющие конструкции), и Petrobras чувствовал необходимость в добавлении к ним полноценного программирования.
Lua 1.0 была спроектирована так, что её конструкторы объектов включали в себя синтаксис языка SOL (отсюда название Lua: по-португальски sol — «солнце», lua — «луна»). Управляющие конструкции Lua были взяты из Modula (if, while, repeat/until), CLU (параллельное присваивание, множественное возвращаемое значение функции как более простая альтернатива вместо передачи параметров по ссылке или явных указателей), C++, SNOBOL и AWK (ассоциативные массивы).
Версии Lua вплоть до 5.0 выпускались под лицензией, подобной лицензии BSD. Начиная с версии 5.0 и выше Lua распространяется под лицензией MIT. Обе лицензии являются пермиссивными и практически идентичны.
Инструменты
Автономный интерпретатор (также называемый lua.c по имени файла исходного кода, или просто lua по исполняемому файлу) представляет собой небольшую программу, позволяющую прямое использование Lua. Когда интерпретатор загружает файл, он игнорирует первую строку, если она начинается со «знака числа» («#»). Эта особенность позволяет использовать Lua как интерпретатор скриптов в Unix-системах. Если вы предваряете свой код строкой вида
(при условии, что автономный интерпретатор расположен в /usr/local/bin ), или
то вы можете вызывать (исполнять) программу напрямую, без необходимости предварительно запускать интерпретатор Lua.
загрузит файл a.lua, затем выполнит присваивание x = 10, и, наконец, предоставит командную строку для ввода.
Основные принципы
Лексические соглашения
Именами (идентификаторами) в Lua могут быть любые строки из букв, цифр и символа подчеркивания, не начинающиеся с цифры. Следующие ключевые слова зарезервированы и не могут быть использованы в именах:
and | break | do | else | elseif |
end | false | for | function | if |
in | local | nil | not | or |
repeat | return | then | true | until |
while |
Lua является языком, чувствительным к регистру символов: and – ключевое слово, тогда как And и AND– два разных допустимых идентификатора. По соглашению, имена, начинающиеся с символа подчеркивания и записанные в верхнем регистре (например _VERSION), зарезервированы для использования в качестве внутренних глобальных переменных, используемых Lua. Литеральные строки должны быть заключены в одинарные или двойные кавычки и могут содержать С-подобные escape-поледовательности.
Типы и переменные
В Lua восемь основных типов: nil (неопределенный), boolean (логический), number (числовой), string (строковый), function (функция), userdata (пользовательские данные), thread (поток), и table (таблица).
Переменные типа table, function, thread и userdata не содержат самих данных, в них хранятся только ссылки на соответствующий объект.
В Lua есть три вида переменных: глобальные, локальные и поля таблиц. Любая переменная считается глобальной, если она явно не объявлена как локальная. Локальные переменные существуют в лексическом контексте: локальные переменные доступны функциям, определенным внутри этого контекста.
Операторы
В Lua поддерживается в общем стандартный набор операторов, почти как в Pascal или C. Он состоит из операторов присваивания, операторов управления потоком исполнения, вызова функций и описания переменных.
Ниже перечислены основные операции:
При сравнении на равенство не производится преобразование типов. Объекты разных типов всегда считаются различными. При вычислении значения используется короткая схема — второй аргумент вычисляется только если это необходимо. Действует следующая таблица приоритетов и ассоциативности операций:
В Lua нет выделенной функции, с которой начинается выполнение программы. Интерпретатор последовательно выполняет операторы, которые он получает из файла или от управляющей программы. При этом он предварительно компилирует программу в двоичное представление, которое также может быть сохранено.
Любой блок кода выполняется как анонимная функция, поэтому в нем можно определять локальные переменные и из него можно возвращать значение.
Операторы можно (но не обязательно) разделять символом ‘;’.
Ниже перечислены основные операторы:
Оператор for выполняется для всех значений переменной цикла начиная от стартового значения и кончая финишным значением включительно. Третье значение, если оно задано, используется как шаг изменения переменной цикла. Все эти значения должны быть числовыми. Они вычисляются только однажды перед выполнением цикла. Переменная цикла локальна в этом цикле и не доступна вне его тела. Значение переменной цикла нельзя изменять внутри тела цикла. Вот псевдокод, демонстрирующий выполнение оператора for :
Функции
Определение функции — это исполняемое выражение (конструктор функции), результатом вычисления которого является объект типа функция:
В скобках размещается список (возможно пустой) аргументов функции. Список аргументов функции может заканчиваться троеточием — в этом случае функция имеет переменное число аргументов. Между закрывающейся скобкой и оператором end размещается тело функции.
В момент выполнения конструктора функции строится также замыкание — таблица всех доступных в функции и внешних по отношению к ней локальных переменных. Если функция передается как возвращаемое значение, то она сохраняет доступ ко всем переменным, входящим в ее замыкание. При каждом выполнения конструктора функции строится новое замыкание.
Вызов функции состоит из ссылки на функцию и заключенного в круглые скобки списка аргументов (возможно пустого). Ссылкой на функцию может быть любое выражение, результатом вычисления которого является функция. Между ссылкой на функцию и открывающейся круглой скобкой не может быть перевода строки.
Если функция принимает единственный аргумент и трактует его как таблицу, элементы которой индексируются именами формальных параметров функции, то в этом случае фактически реализуется вызов механизм поименованных аргументов:
Мета-таблицы
Каждая таблица и объект типа userdata могут иметь мета-таблицу — обычную таблицу, поля которой определяют поведение исходного объекта при применении к нему некоторых специальных операций. Например, когда объект оказывается операндом при сложении, интерпретатор ищет в мета-таблице поле с именем __add и, если такое поле присутствует, то использует его значение как функцию, выполняющую сложение. Индексы (имена полей) в мета-таблице называются событиями, а соответствующие значения (обработчики событий) — метаметодами.
Lua определяет следующие события:
Примеры использования мета-таблиц
В следующем примере мета-таблицы используются для назначения значения по умолчанию для отсутствующих элементов таблицы:
Вот более нетривиальное решение, которое не использует отдельной мета-таблицы для каждого умалчиваемого значения:
Мета-метод __index этой мета-таблицы перехватывает обращения к отсутствующим полям таблицы и возвращает значение, сохраненное в самой таблице по индексу key.
Пакеты
Пакеты — основной способ определять набор взаимосвязанных функций, не загрязняя при этом глобальную область видимости. Обычно пакет представляет собой отдельный файл, который в глобальной области видимости определяет единственную таблицу, содержащую все функции этого пакета:
Также можно делать все функции локальными и отдельно формировать таблицу экспортируемых функций:
Классы и объекты
Конструкция tbl:func() (при объявлении функции и при ее вызове) предоставляет основные возможности, позволяющие работать с таблицей как с объектом. Основная проблема состоит в порождении многих объектов, имеющих сходное поведение т.е. порожденных от одного класса:
Здесь функция class создает пустую таблицу, подготовленную к тому, чтобы стать мета-таблицей объекта. Методы класса делаются полями этой таблицы т.е. класс является таблицей, одновременно содержащей методы объекта и его мета-методы.
Функция object() создает объект заданного класса — таблицу, у которой в качестве мета-таблицы установлен заданный класс. Во втором аргументе может быть передана таблица, содержащая проинициализированные поля объекта.
Стандартные библиотеки
Стандартные Lua библтотеки содержат часто используемые функции, которые выполняются непосредственно в C API. Некоторые из этих функций предоставляют важные сервисы языка (например, type и getmetatable ); другие обеспечивают доступ к «внешним» сервисам (например, ввод/вывод); частично они реализованы на Lua, однако часто используемые и имеющие критическое время выполнения, реализованы на C (например, sort ).
Все библиотеки вызываются через официальный C API и выполняются как отдельные C модули. В настоящий момент, Lua имеет следующие стандартные библиотеки:
Каждая библиотека, исключая базовую и библиотеку пакетов, представляет все функции как поля глобальной таблицы или как методы объектов.
3 – Описание языка
Примечание: В информатике лексический анализ — процесс аналитического разбора входной последовательности символов (например, такой как исходный код на одном из языков программирования) с целью получения на выходе последовательности символов, называемых «токенами» (подобно группировке букв в слова). Группа символов входной последовательности, идентифицируемая на выходе процесса как токен, называется лексемой. В процессе лексического анализа производится распознавание и выделение лексем из входной последовательности символов.
Языковые конструкции будут разъясняться при помощи обычной расширенной BNF нотации, в которой <a> означает 0 или больше символов a, а выражение [a] означает необязательный символ a. Нетерминалы показаны как non-terminal, ключевые слова (keywords) показаны как kword, другие терминальные символы показаны как ‘=’. Полный синтаксис Lua можно найти в §9 в конце этого руководства.
3.1 – Лексические соглашения
Имена (также называемые идентификаторами) в Lua могут быть любой строкой из букв, цифр и символов подчеркивания, но не должны начинаться с цифры. Идентификаторы используются для именования переменных, полей таблиц и меток.
Следующие строки обозначают другие токены: literal strings могут быть заключены соответственно, в одиночные или двойные кавычки, и могут содержать следующие C-подобные escape-последовательности:
Обратный слеш (backslash) с последующим реальным символом новой строки в результате приведут к переносу части строки на новую строку. Escape-последовательность ‘\z‘ пропускает последующий диапазон разделительных (white-space) символов, включая переносы (break) строки; это особенно полезно для прерывания и отступа длинной буквенной (литеральной) строки в многострочном тексте без добавления символов новой строки и пробела в содержимое строки.
Буквенные строки (литералы) также могут быть определены использованием долгого формата заключением в длинные скобки. Мы определяем открывающую длинную скобку уровня вложенности n как открывающую квадратную скобку с последующим n-ным числом знаков равенства, сопровождаемые другой открывающей квадратной скобкой. Так, открывающая длинная скобка уровня 0 записывается как [[, а открывающая длинная скобка уровня 1 записывается как [=[, и так далее. Аналогично определяется и закрывающая длинная скобка; например, закрывающая длинная скобка уровня 4 записывается как ]====]. Длинный литерал начинается с открывающей длинной скобки любого уровня и заканчивается первой закрывающей длинной скобкой того же уровня. Она может содержать любой текст, кроме закрывающей скобки того же уровня. Литералы в этой «скобочной» форме могут продолжаться до нескольких строк, в них не выполняется интерпретация любых управляющих последовательностей и игнорируются длинные скобки любого другого уровня. Любой тип управляющей последовательности окончания строки (возврат каретки, новая строка, возврат каретки, сопровождаемый новой строкой, или новая строка с последующим возвратом каретки) преобразуется в простой символ новой строки.
Любой байт в литеральной строке, явно не затронутые предыдущими правилами, представляет самого себя. Однако, Lua открывает файлы для анализа (парсинга) в текстовом режиме и у функций системных файлов могут возникать проблемы с некоторыми управляющими символами. Так что более безопаснее представлять не текстовые данные в виде закавыченных литералов с явно указанными управляющими последовательностями для нетекстовых символов.
3.2 – Переменные
Одиночное (отдельное) имя может обозначать глобальную переменную или локальную переменную (или формальный (т.е. соответствующий правилам) параметр функции, который является особым видом локальной переменной): Name обозначает идентификаторы, как было определено в §3.1.
Любая переменная name предполагается глобальной, если явно не объявлена как локальная (смотрите §3.3.7). Локальные переменные ограничены лексически: локальные переменные могут быть свободно доступны функциям, определенным внутри их области видимости (смотрите §3.5).
Перед первым присваиванием переменной, её значением является nil.
Квадратные скобки используются для обозначения индексов таблицы: Значение обращений к полям таблицы может быть изменено с помощью метатаблиц. Обращение к индексированной переменной t[i] аналогично вызову gettable_event(t,i) (смотрите §2.4 с полным описанием функции gettable_event. Эта функция не определена и не подлежит вызову в Lua. Здесь она приведена только в разъяснительных целях.)
3.3 – Операторы
3.3.1 – Блоки
3.3.2 – Порции
Порция может быть сохранена в файл или строку внутри хост-программы. Для выполнения порции (chunk), Lua сначала загружает её, предварительно компилируя код порции в инструкции для виртуальной машины, и затем Lua выполняет скомпилированный код с интерпретатором виртуальной машины.
Порции также можно предварительно скомпилировать в двоичную форму; для более подробных сведений смотрите программу luac и функцию string.dump. Программы в исходной и компилированной формах взаимозаменяемы; Lua автоматически распознает тип файла и действует соответственно (смотрите load).
т.е. — пооператорный (покомандный, построчный) анализ, обработка и тут же выполнение исходной программы или запроса (в отличие от компиляции, при которой программа транслируется без её выполнения).
Простой интерпретатор анализирует и тут же выполняет (собственно интерпретация) программу покомандно (или построчно), по мере поступления её исходного кода на вход интерпретатора. Достоинством такого подхода является мгновенная реакция. Недостаток — такой интерпретатор обнаруживает ошибки в тексте программы только при попытке выполнения команды (или строки) с ошибкой.
Интерпретатор компилирующего типа — это система из компилятора, переводящего исходный код программы в промежуточное представление, например, в байт-код или p-код, и собственно интерпретатора, который выполняет полученный промежуточный код (так называемая виртуальная машина). Достоинством таких систем является большее быстродействие выполнения программ (за счёт выноса анализа исходного кода в отдельный, разовый проход, и минимизации этого анализа в интерпретаторе). Недостатки — большее требование к ресурсам и требование на корректность исходного кода.
3.3.3 – Присваивание
Lua разрешает множественные присваивания. Поэтому, синтаксис присваивания определяет список переменных с левой стороны, а список выражений с правой стороны. Элементы в обоих списках разделяются запятыми: Выражения обсуждаются в §3.4.
Перед присваиванием список значений согласовывается с длиной списка переменных. Если значений больше чем нужно, избыточные значения отбрасываются. Если значений меньше чем требуется, в список добавляются значения nil до нужного количества. Если список выражений оканчивается вызовом функции, то все значения возвращаемые этим вызовом вводятся в список значений, перед согласованием (кроме случаев, когда вызов заключен в круглые скобки; смотрите §3.4).
Оператор присваивания сначала вычисляет все свои выражения и только затем присваивание выполняется. Таким образом, код устанавливает a[3] равным 20, не затрагивая a[4], так как i в a[i] вычисляется (как 3) перед присвоением ему 4. Аналогично, строка обменивает значения x и y, а циклически переставляет значения x, y, и z.
Значение присваиваний глобальным переменным и полям таблиц может быть изменено с помощью метатаблиц. Присваивание индексированной переменной t[i] = val эквивалентно settable_event(t,i,val). (смотрите в §2.4 полное описание функции settable_event. Эта функция в Lua не определяется и не вызывается, она используется здесь только в разъяснительных целях.)
Присваивание глобальному имени x = val эквивалентно присваиванию _ENV.x = val (смотрите §2.2).
3.3.4 – Управляющие структуры
Управляющие структуры if, while, и repeat имеют обычное значение и знакомый синтаксис:
В Lua также имеется оператор цикла for, в двух вариантах (смотрите §3.3.5).
Условное выражение управляющей структуры может возвращать любое значение. Значения false и nil считаются ложными. Все значения, отличные от nil и false считаются истинными (в частности, число 0 и пустая строка также являются истинными).
В цикле repeat–until, внутренний блок завершается не при достижении ключевого слова until, а только после выполнения условия. Так что, условие может ссылаться на локальные переменные, объявленные внутри блока цикла.
Оператор goto передает управление программой на метку (label). По синтаксическим причинам, метки в Lua также считаются операторами: Метка является видимой во всем блоке, где она объявлена, за исключением мест внутри вложенных блоков, где определена метка с таким же именем, и внутри вложенных функций. goto может перейти на любую видимую метку до тех пор, пока не входит в область видимости локальной переменной.
Метки и пустые операторы называются недействующими операторами (void statements), так как они не выполняют действий.
Оператор break завершает выполнение while, repeat, или цикла for, переходя к следующему оператору после цикла: break завершает самый внутренний вложенный цикл.
Оператор return используется для возврата значений из функции или порции (которая является анонимной функцией). Функции могут возвращать более одного значения, так что синтаксис для оператора return таков Оператор return может быть записан только в качестве последнего оператора блока. Если действительно необходимо, чтобы return был в середине блока, то можно использовать явно заданный внутренний блок, в виде идиомы do return end, так как теперь return является последним оператором в своем (внутреннем) блоке.
3.3.5 – Оператор for
Оператор цикла for имеет две формы: числовую и универсальную (типовую).
3.3.6 – Вызовы функций как операторы
3.3.7 – Локальные объявления
Локальные переменный могут быть объявлены в любом месте внутри блока. Объявление может включать начальное присваивание: Если таковое существует, начальное присваивание имеет ту же семантику как и множественное присваивание (смотрите §3.3.3). В противном случае, все переменные инициализируются со значением nil.
Порция также является блоком (смотрите §3.3.2) и поэтому локальные переменные могут быть объявлены в порции за пределами любого явного блока.
Правила видимости для локальных переменных поясняются в §3.5.
3.4 – Выражения
Основные выражения в Lua следующие: Числа и символьные строки (литеральные строки) описаны в §3.1; переменные в §3.2; определения функций описаны в §3.4.11; вызовы функций в §3.4.10; конструкторы таблиц описываются в §3.4.9. Выражения с переменным числом аргументов (vararg), обозначаемые тремя точками (‘. ‘), могут использоваться только непосредственно внутри функций с переменным числом аргументов (vararg function); они поясняются в §3.4.11.
В бинарные операторы включены арифметические операторы (смотрите §3.4.1), побитовые операторы (смотрите §3.4.2), операторы сравнения (смотрите §3.4.4), логические операторы (смотрите §3.4.5), и оператор конкатенации (смотрите §3.4.6). В унарные операторы включены унарный минус (смотрите §3.4.1), унарный побитовый НЕ (смотрите §3.4.2), унарный логический not (смотрите §3.4.5), и унарный оператор длины (смотрите §3.4.7).
И вызовы функций, и выражения с переменным числом аргументов (vararg expressions) могут приводить к множеству значений. Если вызов функции используется как оператор (смотрите §3.3.6), то его список возврата устанавливается в ноль элементов, таким образом отбрасываются все возвращаемые значения. Если выражение используется в качестве последнего (или единственного) элемента списка выражений, то такая корректировка не делается (если выражение не заключено в круглые скобки). Во всех других ситуациях, Lua сводит список результатов к одному элементу, либо отбрасывая все значения за исключением первого из них, либо добавляя одиночный nil, если значений не существует.
Вот некоторые примеры: Любые выражения заключенные в круглые скобки всегда выдают только одно значение. Таким образом, (f(x,y,z)) это всегда одно значение, даже если f возвращает несколько значений. (Значением из (f(x,y,z)) является первым значением, возвращенным f или значение nil, если f не возвратит никаких значений.)
3.4.1 – Арифметические операторы
Возведение в степень и деление чисел с плавающей запятой (/) всегда конвертирует свои операнды в числа с плавающей запятой и всегда получает результат в виде числа с плавающей запятой. Возведение в степень использует ISO C функцию pow, так что он также работает и с нецелочисленными показателями степени.
Модуль определяется как остаток от деления, при котором частное округляется в направлении к минус бесконечности. (деление с округлением вниз).
В случае переполнений (когда для представления получившегося числа не хватает разрядности) в целочисленной арифметике, все операции циклически переносятся (wrap around), в соответствии с обычными правилами арифметики дополнительных кодов. (Другими словами, они возвращают уникальное представляемое целое число, равное остатку от деления 2 64 на результат математического вычисления.)
3.4.2 – Побитовые операторы
Lua также конвертирует строки в числа всякий раз, когда предполагается число.
В преобразовании целого числа в число с плавающей запятой, если целочисленное значение имеет точное представление как число с плавающей запятой, то оно и будет результатом преобразования. В другом случае, при преобразовании получается ближайшее большее или ближайшее меньшее число от представленного значения. Преобразования такого рода никогда не делают ошибок.
При преобразовании числа с плавающей запятой в целое число проверяется, не имеет ли число с плавающей запятой точного представления в виде целого числа (то есть проверяется, что число с плавающей запятой имеет целочисленное значение и оно находится в диапазоне целочисленных представлений). Если это так, то это представление и является результатом. В противном случае преобразование завершается неудачей.
Преобразование строк в числа происходит следующим образом: Вначале, строка конвертируется в целое число или число с плавающей запятой, следуя своему синтаксису и правилам лексического анализатора Lua. (Строка также может иметь начальные или конечные пробелы и знак.) Затем, полученное число (целое или с плавающей запятой) преобразуется в тип (целое число или число с плавающей запятой), требуемый по контексту (например, операцией, которая вызвала преобразование).
Преобразование чисел в строки использует не указанный удобочитаемый формат. Для полного управления тем, как числа преобразуются в строки, используйте функцию format из строковой библиотеки (смотрите string.format).
3.4.4 – Операторы сравнения
Равенство (==) вначале сравнивает тип своих операндов. Если типы различны, то в результате выдается false. В противном случае сравниваются значения операндов. Строки сравниваются банальным способом. Числа равны, если они означают одно и тоже математическое значение.
Таблицы, userdata и нити (потоки) сравниваются по ссылке: два объекта считаются равными, только если они являются одним и тем же объектом. Каждый раз при создании нового объекта (таблица, userdata или нить), этот новый объект отличается от любого, уже существующего объекта. Замыкания с одной и той же ссылкой всегда равны. Замыкания с любой обнаруженной разницей (разное поведение, разное определение) всегда различны.
Изменить способ, которым Lua сравнивает таблицы и userdata, можно при помощи метаметода «eq» (смотрите §2.4).
При сравнениях на равенство не производится конвертирование строк в числа и наоборот. Таким образом, "0"==0 определяется как false, а t[0] и t["0"] обозначают разные записи в таблице.
= является точным отрицанием равенства (==).
Операторы порядка работают следующим образом. Если оба аргумента являются числами, то они сравниваются в соответствии с их математическими значениями (не обращая внимания на их подтипы). Иначе, если оба аргумента являются строками, то их значения сравниваются в соответствии с текущей локалью. В противном случае, Lua пытается вызвать метаметод «lt» или «le»смотрите §2.4). Сравнение a > b преобразуется в b = b преобразуется в b указывает на результат предыдущего выражения.)
3.4.6 – Конкатенация
3.4.7 – Оператор длины
Оператор длины обозначается одиночным оператором-приставкой #. Длиной строки является количество байт в ней (то есть, обычное значение длины строки, когда каждый из символов занимает один байт).
Программа может изменять поведение оператора длины для любого значения, а для строк через метаметод __len (смотрите §2.4).
Если не задан метаметод __len, длина таблицы t определяется только если таблица является последовательностью, то есть, набор её положительных цифровых ключей равен для некоторого неотрицательного целого числа n. В этом случае, n является её длиной. Обратите внимание, что таблица вроде не является последовательностью, так как она имеет ключ 4, но не имеет ключа 3. (Так как не существует такого n, что набор равен набору положительных цифровых ключей этой таблицы.) Отметьте впрочем, что нечисловые ключи не мешают таблице быть последовательностью.
3.4.8 – Приоритет
реализуемая когда операции имеют одинаковый приоритет и отсутствует явное (с помощью скобок) указание на очерёдность их выполнения. Ассоциативность (от лат. associatio) — свойство операций, позволяющее восстановить последовательность их выполнения при отсутствии явных указаний на очерёдность при равном приоритете; при этом различается левая ассоциативность, при которой вычисление выражения происходит слева направо, и правая ассоциативность — справа налево. Соответствующие операторы называют левоассоциативными и правоассоциативными.
3.4.9 – Конструкторы таблиц
Если последнее поле в списке имеет форму exp и это выражение является вызовом функции или выражением с переменным числом аргументов (vararg выражением), то все значения, возвращенные этим выражением, последовательно вводятся в список (смотрите §3.4.10).
Поле списка может иметь необязательный завершающий разделитель, для удобства при машинной генерации кода.
3.4.10 – Вызовы функций
Вызов функции в Lua имеет следующий синтаксис: или на русском языке В вызове функции, сначала вычисляются префиксные выражения (prefixexp) и аргументы (args). Если значение prefixexp имеет тип function, то эта функция вызывается с заданными аргументами. В противном случае, prefixexp вызывает метаметод «call», имеющий в качестве первого параметра значение prefixexp, с последующим вызовом исходных аргументов (смотрите §2.4).
Форма записи может использоваться для вызова «методов». Вызов в виде v:name(args) это «синтаксический сахар» для v.name(v,args), за исключением того, что v вычисляется только один раз.
Вызов в виде return functioncall называется хвостовым вызовом (tail call). В Lua реализованы правильные хвостовые вызовы (или правильная хвостовая рекурсия): в хвостовом вызове, вызываемая функция повторяет запись стека вызывающей функции. Поэтому не существует ограничения на число вложенных хвостовых вызовов, которые может выполнить программа. Однако, хвостовой вызов стирает любую отладочную информацию о вызывающей функции. Обратите внимание, что хвостовой вызов происходит только при конкретном синтаксисе, где return в качестве аргумента имеет один, единственный вызов функции; такой синтаксис делает возврат вызывающей функции в точности равным возврату вызываемой функции. Так что, ни один из следующих примеров не является хвостовым вызовом:
3.4.11 – Определения функций
Синтаксис определения функции Следующий «синтаксический сахар» упрощает определения функций: Заявление преобразуется в Заявление преобразуется в Заявление преобразуется в а не в (Различие появляется только когда тело функции содержит ссылки на f.)
Параметры действуют как локальные переменные, которые инициализированы значениями аргументов: При вызове функции список аргументов корректируется по длине со списком параметров, если функция не является функцией с переменным числом аргументов (vararg функция), которая обозначается тремя точками (‘. ‘) в конце своего списка параметров. Функция с переменным числом аргументов не корректирует список своих аргументов; вместо этого, она собирает все дополнительные аргументы и передает их в функцию через выражение с переменным числом аргументов (vararg выражение), которое также обозначается как три точки. Значением этого выражения является список всех текущих дополнительных аргументов, похожий на функцию с множественным результатом. Если выражение с переменным числом аргументов используется внутри другого выражения или в середине списка выражений, то его список возврата сводится к одному элементу. Если выражение используется как последний элемент в списке выражений, то такая корректировка не производится (если это последнее выражение не заключено в круглые скобки).
В качестве примера рассмотрим следующие определения: Далее получаем следующее сопоставление от аргументов к параметрам и vararg выражению: Результаты возвращены при помощи оператора return (смотрите §3.3.4). Если управление доходит до конца функции не встречая оператор return, то функция ничего не возвращает.
Существует системно-зависимый предел на число значений, которые может возвращать функция. Этот предел гарантированно больше 1000.
Синтаксис с двоеточием используется для определения методов, то есть, функций, имеющих неявный дополнительный параметр self. Таким образом, выражение это «синтаксический сахар» для
3.5 – Правила видимости
Lua является языком программирования с лексическим разграничением. Область видимости локальной переменной начинается с первого оператора после её объявления и продолжается до последнего не пустого оператора самого внутреннего блока, который включает объявление. Рассмотрим следующий пример: Обратите внимание, что в объявлении local x = x, новая переменная x будучи объявлена, ещё не находится в области видимости, и поэтому второй x относится к внешней переменной.
Из-за правил лексического разграничения, локальные переменные могут быть широко доступны функциям, определенным в их области видимости. Локальная переменная используемая внутренней функцией называется upvalue, или внешней локальной переменной, внутри вложенной функции.
Заметьте, что каждое выполнение оператора local определяет новую локальную переменную. Рассмотрим следующий пример: Цикл создает десять замыканий (closure) (то есть, десять экземпляров анонимной функции). Каждый из этих замыканий использует разную переменную y, хотя все они используют одну и ту же переменную x.
в окружающем коде и не являющиеся её параметрами. Говоря другим языком, замыкание — функция, которая ссылается на свободные переменные в своём контексте.
Замыкание, так же как и экземпляр объекта, есть способ представления функциональности и данных, связанных и упакованных вместе.
Замыкание — это особый вид функции. Она определена в теле другой функции и создаётся каждый раз во время её выполнения. Синтаксически это выглядит как функция, находящаяся целиком в теле другой функции. При этом вложенная внутренняя функция содержит ссылки на локальные переменные внешней функции. Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
В случае замыкания ссылки на переменные внешней функции действительны внутри вложенной функции до тех пор, пока работает вложенная функция, даже если внешняя функция закончила работу, и переменные вышли из области видимости.
Замыкание связывает код функции с её лексическим окружением (местом, в котором она определена в коде). Лексические переменные замыкания отличаются от глобальных переменных тем, что они не занимают глобальное пространство имён. От переменных в объектах они отличаются тем, что привязаны к функциям, а не объектам.