Переменные в Lua


Содержание

Переменные в Lua

До сих пор при необходимости задействовать какую-либо переменную мы просто присваивали ей значение:

При этом использовались так называемые глобальные переменные. Такие переменные видны отовсюду, то есть, к их значениям можно обращаться из любого места программы. Однако, например, переменная-счётчик из рассмотренного в прошлой статье числового цикла for таковой не является: её областью видимости является только блок внутри for. То есть:

Переменная, область видимости которой ограничена блоком кода, называется локальной для этого блока. Так, при использовании числового for автоматически объявляется локальная переменная-счётчик.

Локальную переменную можно объявить и вручную. При этом, пока ей не присвоится значение, она будет иметь значение nil.

Также существует возможность создать блок безо всяких управляющих конструкций:

Если во вложенном блоке объявить переменную с именем, которое уже занято какой-то другой переменной, объявленной снаружи, то новая переменная перекроет старую. Другими словами, при обращении к какой-либо переменной ищется ближайшая по глубине вложенности переменная с указанным именем. Если не нашлось ни одной локальной, то используется глобальная.

Если объявить локальную переменную вне всяких блоков, она будет локальной для данного файла.

(Да, строго говоря, в общем случае не для файла, а для чанка — куска кода, обрабатываемого “за раз”. При работе с командной строкой Lua чанком будет являться одна введённая строка, а в случае исполнения файла целиком — весь файл. Кстати, разбиение программы на несколько файлов (модулей) будет рассмотрено позже.)

Стоит, наверное, отметить, что “жизнь” переменной начинается именно с той строки, в которой её объявили. То есть, здесь не происходит неявного поднятия (hoisting) объявления переменной в начало блока, как в JavaScript при использовании var.

Глобальные переменные обычно используются для предоставления разработчику некоторых стандартных функций языка и других средств для “общения с внешним миром”. Например, переменные print, pairs, ipairs являются глобальными. В целом, хорошим тоном считается не создавать новые глобальные переменные без крайней необходимости, а объявлять и использовать локальные. На это есть как минимум три причины:

Обращение к локальным переменным происходит быстрее. При одном обращении это не так важно, но если глобальные переменные, например, используются в цикле, то негативный эффект может быть очень заметным.

В больших программах засорение глобального пространства имён вынуждает следить, чтобы все используемые глобальные переменные имели разные имена. Иначе это может привести к тому, что разный код будет конфликтовать, пытаясь обратиться к одним и тем же переменным. Лучше, когда каждый модуль работает в своём предсказуемом пространстве. Особенно это актуально при написании библиотек, которые подразумевают использование их другими людьми.

Читаемость кода: чем меньше область видимости у переменной, тем проще понять, где и для чего она используется. По этой же причине желательно объявлять переменную как можно ближе к её использованию вместо того, чтобы разом объявлять все используемые переменные в начале блока.

Ещё одна деталь. Из-за того, что обращение к неопределённым глобальным переменным не вызывает ошибки, следует быть внимательнее при указании имён переменных, так как при опечатке есть возможность “промахнуться” по нужной переменной и попасть в глобальную, которая равна nil. А это может обнаружиться не сразу и в неожиданном месте.

Кстати, ещё о глобальных переменных. Вы заметили, что неопределённые глобальные переменные ведут себя точно так же, как незаданные значения в таблицах? Они тоже изначально равны nil, и установка значения nil эквивалентна удалению элемента. Это совпадение на самом деле не случайно: значения всех глобальных переменных действительно хранятся в специальной таблице. Обратиться к этой таблице можно через глобальную переменную _G:

Так как обращение к глобальной переменной — это ни что иное, как обращение к элементу хеш-таблицы, а локальные переменные по сути берутся из массива по индексу (они хранятся в регистрах виртуальной машины), неудивительно, что второе происходит быстрее.

(Кстати, подробности реализации виртуальной машины Lua 5.0 можно почитать здесь. Думаю, большая часть написанного до сих пор актуальна как для современных официальных реализаций, так и для LuaJIT.)

Дополнительная информация для любознательных. Тут может появиться закономерный вопрос: если именно локальные переменные считаются более предпочтительными в большинстве случаев, то почему тогда переменные создаются глобальными “по умолчанию”, а для объявления локальной переменной требуется использовать дополнительное слово local? Вроде, логичнее было бы наоборот, как это сделано, например, в Python. Там присваивание к необъявленной переменной автоматически объявляет её как локальную, а для объявления глобальной переменной существует ключевое слово global.

Одна из причин такого решения в Lua заключается в лучшей читаемости кода. Без явных указаний, что происходит объявление локальной переменной, трудно сказать, глядя на код, для какого именно блока переменная является локальной. Инструкция присваивания в этом случае может как изменять существующую переменную с целью повлиять на внешний код, так и объявлять новую локальную переменную, использующуюся только внутри этого блока. Явная же инструкция local позволяет видеть, что жизнь переменной начинается именно здесь.

Другая, более серьёзная проблема возникает при попытке изменить во вложенном блоке значение внешней переменной простым присваиванием. Если инструкция присваивания включает в себя объявление переменной, то в этом случае она без спроса объявляет ещё одну локальную переменную с тем же именем, чем нарушает наши планы (и, как следствие, требуется дополнительный костыль для явного изменения значения внешней переменной, вроде nonlocal в Python). Ещё есть вариант — допустить, чтобы при существовании внешней переменной с указанным именем язык обращался к ней, а не объявлял новую. Но в этом случае всё равно потребовалось бы ключевое слово для явного объявления переменной, чтобы была возможность при необходимости принудительно перекрыть существующую переменную. А если такое слово ввести, то все эти сложности с совмещённым присваиванием и объявлением снова перестают иметь смысл.

В общем, явное объявление локальных переменных показалось разработчикам языка более приемлемым вариантом. Другой вопрос в том, правильным ли было решение создавать глобальные переменные по умолчанию и отдавать nil при обращении к несуществующей переменной. Ведь именно возможность случайно “выпасть” в глобальную переменную беспокоит больше всего. Однако, к счастью, в этом отношении поведение языка можно при необходимости изменить. Этот трюк будет рассмотрен в одной из следующих статей.

Использование локальных переменных в Lua

Локальные переменные в языке Lua являются очень быстрыми, поскольку они находятся в виртуальном регистрах машины и доступны по индексу. Глобальные переменные, напротив, находятся в таблице глобальных переменных Lua и доступны лишь хешированием.

Поэтому везде, где требуется интенсивный доступ к переменным, следует использовать переменные с локальной видимостью взамен глобальных. Особенно это актуально для переменных, обращение к которым происходит в циклах.

По умолчанию все переменные в Lua глобальны. Чтобы сделать переменную локальной, она должна быть явно описана как local.

Вот фрагмент кода, который в том или ином варианте встречается в каждой программе на lua:

Чтобы сэкономить порядка 10% процессорного времени, необходимого для выполнения этого фрагмента, имеет смысл заменить глобальный итератор next() на его локальную копию:


Похожая ситуация с require. Имеет смысл присвоить локальной переменной результат, возвращаемый функцией require:

Вопрос по lua &#8211 как назначить переменную lua по ссылке

Как я могу назначить переменную по ссылке в Lua другой?

Например: хотите сделать эквивалент & quot; a = b & quot; где а будет указатель на б

Фон: есть случай, когда у меня есть что-то вроде этого:

PS. Например, ниже показано, что b = a является значением. ПРИМЕЧАНИЕ. Я использую Corona SDK.

что переменные являются просто именами для значений. Но вы можете вычислить имена переменных, если вы имеете дело с ключами в таблице. Это означает, что вы можете использовать имена ключей для выполнения вашей условной логики.

в отношении вашего поясненного поста и примера, в Lua нет такой вещи, как тип ссылки, который вы хотите. Вы хотите, чтобы переменная ссылалась на другую переменную. В Lua переменные — это просто имена для значений. Вот и все.

Следующее работает, потому что b = a оставляет оба a а также b ссылаясь на то же значение таблицы:

Вы можете думать обо всех переменных назначений в Lua как по ссылке.

Технически это верно для таблиц, функций, сопрограмм и строк. Этоmay as well будьте верны с числами, логическими значениями и нулем, потому что они являются неизменяемыми типами, поэтому для вашей программы разницы нет.

Краткая версия: это имеет практическое значение только для изменчивых типов, которые в Lua — это userdata и table. В обоих случаях присвоение копирует ссылку, а не значение (то есть не клон или копию объекта, а присвоение указателя).

Love2D: Область видимости и локальные переменные

Руководство по Lua 5.1
  • Типы в Lua
  • Присваивание
  • Работа с числами
  • Работа со строками
  • Операторы в Lua
  • Управляющие конструкции
  • Работа с таблицами
  • Подробнее о функциях
  • Область видимости и локальные переменные
  • Метатаблицы и метаметоды
  • ООП в LUA


Создание локальной переменной

Локальные функции — синтаксический сахар

Замыкания

В этом примере мы расскатриваеи Button как инструментарий функции для создания новой кнопки.
label обозначение кнопки; action функция обратного вызова при нажатии. (В действительности это замыкание, т.к. имеет доступ к ВЛП digit). Функция обратного вызова может быть вызвана и через некоторое время после того, как digitButton выполнит свою задачу а локальная переменная digit выйдет из области видимости. но всё равно она будет иметь доступ к этой переменной.

=== Когда стоит использовать локальные переменные? ===

Как сохранить и прочитать переменные в файле? lua

Как сохранить их и прочитать в файле?

1 ответ 1

Пример чтения файла

Считывание данных можно сократить, используя строки форматирования

Пример записи файла (при ошибке передаст её вызывателю)

Илон Маск рекомендует:  Что такое код farheapchecknode

Всё ещё ищете ответ? Посмотрите другие вопросы с метками lua или задайте свой вопрос.

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2020 Stack Exchange Inc; пользовательское содержимое попадает под действие лицензии cc by-sa 4.0 с указанием ссылки на источник. rev 2020.11.11.35399

Santa Simplicita

Просто писать о простом — не так и просто…

Lua за 60 минут

Я сентиментальный программист. Иногда я влюбляюсь в языки программирования, и тогда я могу говорить о них часами. Одним из этих часов я поделюсь с вами.

Lua? Что это?

Lua — простой встраиваемый язык (его можно интегрировать с вашими программами, написанными на других языках), легкий и понятный, с одним типом данных, с однообразным синтаксисом. Идеальный язык для изучения.

Зачем?

Lua может вам пригодится:

* если вы геймер (плагины для World of Warcraft и множества других игр)
* если вы пишете игры (очень часто в играх движок пишут на C/C++, а AI — на Lua)
* если вы системный программист (на Lua можно писать плагины для nmap, wireshark, nginx и других утилит)
* если вы embedded-разработчик (Lua очень быстрый, компактный и требует очень мало ресурсов)

Что надо для того, чтобы читать дальше?

1. Научитесь программировать. Хотя бы немного. Не важно на каком языке.
2. Установите Lua. Для этого либо скачайте здесь версию 5.2 (http://www.lua.org/download.html), либо ищите ее в репозиториях. Версия 5.1 тоже пойдет, но знайте, что она очень старая.

Все примеры из статьи запускайте в терминале командой наподобие «lua file.lua».


Первые впечатления

Lua — язык с динамической типизацией (переменные получают типы «на лету» в зависимости от присвоенных значений). Писать на нем можно как в императивном, так и в объектно-ориентированном или функциональном стиле (даже если вы не знаете как это — ничего страшного, продолжайте читать). Вот Hello world на Lua:

Что уже можно сказать о языке:

* однострочные комментарии начинаются с двух дефисов «—»
* скобки и точки-с-запятыми можно не писать

Операторы языка

Набор условных операторов и циклов довольно типичен:

ПОДУМАЙТЕ: что может означать цикл «for i = 1, 10, 2 do . end» ?

В выражениях можно использовать такие вот операторы над переменными:

* присваивание: x = 0
* арифметические: +, -, *, /, % (остаток от деления), ^ (возведение в степень)
* логические: and, or, not
* сравнение: >, =,

= (не-равно, да-да, вместо привычного «!=»)
* конкатенация строк (оператор «..»), напр.: s1=»hello»; s2=»world»; s3=s1..s2
* длина/размер (оператор #): s=»hello»; a = #s (‘a’ будет равно 5).
* получение элемента по индексу, напр.: s[2]

Битовых операций в языке долгое время не было, но в версии 5.2 появилась библиотека bit32, которая их реализует (как функции, не как операторы).

Типы данных

Я вам соврал, когда сказал что у языка один тип данных. Их у него много (как и у каждого серьезного языка):

* nil (ровным счетом ничего)
* булевы числа (true/false)
* числа (numbers) — без деления на целые/вещественные. Просто числа.
* строки — кстати, они очень похожи на строки в паскале
* функции — да, переменная может быть типа «функция»
* поток (thread)
* произвольные данные (userdata)
* таблица (table)

Если с первыми типами все понятно, то что же такое userdata? Вспомним о том, что Lua — язык встраиваемый, и обычно тесно работает с компонентами программ, написанными на других языках. Так вот, эти «чужие» компоненты могут создавать данные под свои нужды и хранить эти данные вместе с lua-объектами. Так вот, userdata — и есть подводная часть айсберга, которая с точки зрения языка lua не нужна, но и просто не обращать внимания на нее мы не можем.

А теперь самое важное в языке — таблицы.

Таблицы

Я вам снова соврал, когда сказал, что у языка 8 типов данных. Можете считать что он один: всё — это таблицы (это, кстати, тоже неправда). Таблица — это очень изящная структура данных, она сочетает в себе свойства массива, хэш-таблицы («ключ»-«значение»), структуры, объекта.

ПОДУМАЙТЕ: чему равно a[2] в случае разреженного массива?

В примере выше таблица ведет себя как массив, но на самом деле — у нас ведь есть ключи (индексы) и значения (элементы массива). И при этом ключами могут быть какие угодно типы, не только числа:

Кстати, раз уж у таблицы есть ключи и значения, то можно в цикле перебрать все ключи и соответствующие им значения:

А как же объекты? О них мы узнаем чуть позже, вначале — о функциях.

Функции

Вот пример обычной функции.

Функции языка позволяют принимать несколько аргументов, и возвращать несколько аргументов. Так аргументы, значения которых не указаны явно, считаются равными nil.

ПОДУМАЙТЕ: зачем может понадобиться возвращать несколько аргументов?

Функции могут принимать переменное количество аргументов:


Поскольку функции — это полноценный тип данных, то можно создавать переменные-функции, а можно передавать функции как аргументы других функций

Объекты = функции + таблицы

Раз мы можем сохранять функции в переменных, то и в полях таблиц тоже сможем. А это уже получаются как-бы-методы. Для тех, кто не знаком с ООП скажу, что основная его польза (по крайней мере в Lua) в том, что функции и данные, с которыми они работают находятся рядом — в пределах одного объекта. Для тех, кто знаком с ООП скажу, что классов здесь нет, а наследование прототипное.

Перейдем к примерам. Есть у нас объект, скажем, лампочка. Она умеет гореть и не гореть. Ну а действия с ней можно сделать два — включить и выключить:

А если лампочку сделать объектом, и функции turn_off и turn_on сделать полями объекта, то получится:

Мы вынуждены передавать сам объект лампочки в качестве первого аргумента, потому что иначе наша функция не узнает с какой именно лампочкой надо работать, чтобы сменить состояние on/off. Но чтобы не быть многословными, в Lua есть сокращенная запись, которую обычно и используют — lamp:turn_on(). Итого, мы уже знаем несколько таких упрощений синтаксиса:

Продолжая говорить о сокращениях, функции можно описывать не только явно, как поля структуры, но и в более удобной форме:

Специальные функции

Некоторые имена функций таблиц (методов) зарезервированы, и они несут особый смысл:

* __add(a, b), __sub(a, b), __div(a, b), __mul(a, b), __mod(a, b), __pow(a, b) — вызываются, когда выполняются арифметические операции над таблицей
* __unm(a) — унарная операция «минус» (когда пишут что-то типа «x = -x»)
* __lt(a, b), __le(a, b), __eq(a, b) — вычисляют результат сравнения ( «+» , а не «..» . Для этого надо подменить функцию «+» (__add) для родительской таблицы всех строк:

Собственно, мы еще можем заменить функцию print с помощью «print = myfunction», да и много других хакерских дел можно сделать.

Области видимости

Переменные бывают глобальные и локальные. При создании все переменные в Lua являются глобальными.

Для указания локальной области видимости пишут ключевое слово local:

Не забывайте об этом слове.

Обработка ошибок

Часто, если возникают ошибки, надо прекратить выполнение определенной функции. Можно, конечно, сделать множество проверок и вызывать «return», если что-то пошло не так. Но это увеличит объем кода. В Lua используется что-то наподобие исключений (exceptions).

Ошибки порождаются с помощью функции error(x). В качестве аргумента можно передать все, что угодно (то, что имеет отношение к ошибке — строковое описание, числовой код, объект, с которым произошла ошибка и т.д.)

Обычно после этой функции вся программа аварийно завершается. А это надо далеко не всегда. Если вы вызываете функцию, которая может создать ошибку (или ее дочерние функции могут создать ошибку), то вызывайте ее безопасно, с помощью pcall():

Стандартные библиотеки

Стандартных библиотек мало, зато это позволяет запускать Lua где угодно. Подробнее можно получить их список здесь — http://www.lua.org/manual/5.2/manual.html

Нестандартных библиотек много, их можно найти на LuaForge, LuaRocks и в других репозиториях.

Между Lua и не-Lua

ВНИМАНИЕ: эту часть рекомендуется читать людям со знанием языка C.

А если нам недостаточно функциональности стандартных библиотек? Если у нас есть наша программа на C, а мы хотим вызывать ее функции из Lua? Для этого есть очень простой механизм.

Допустим, мы хотим создать свою функцию, которая возвращает случайное число (в Lua есть math.random(), но мы хотим поучиться). Нам придется написать вот такой код на C:

Т.е. Lua предоставляет нам функции для работы с типами данных, для получения аргументов функций и возврата результатов. Функций очень мало, и они довольно простые. Теперь мы собираем нашу библиотеку как динамическую, и можем использовать функцию rand():


А если мы хотим вызывать код, написанный на Lua из наших программ? Тогда наши программы должны создавать виртуальную машину Lua, в которой и будут выполняться Lua-скрипты. Это намного проще:

Вы теперь можете писать на Lua. Если вы узнаете интересные моменты про Lua, которые можно было бы отразить в статье — пишите!

Язык Lua и Corona SDK (1/3 часть)

Если вы решили освоить разработку игр с использованием Corona SDK, эта статья даст вам необходимые основы самого движка и языка Lua, на котором вам придется разрабатывать. По своему этот язык прекрасен и во многих отношениях необычен. Я постарался собрать в одну статью все наиболее необходимые сведения, но их оказалось больше чем можно размещать в одной публикации и мне пришлось разделить статью на 3 части, эта первая часть и в ней мы рассмотрим следующие вопросы:

  • Порядок комментирования исходников
  • Переменные, константы, область видимости
  • Модули и организация проекта
  • Условные операторы

Порядок комментирования исходников

Почти в любом языке программирования имеется понятие комментариев, Lua не исключение. Что вообще такое комментарий — это пояснения к исходному тексту программы, находящиеся непосредственно внутри комментируемого кода. Синтаксис комментариев определяется языком программирования. С точки зрения компилятора или интерпретатора, комментарии — часть текста программы, не влияющая на её семантику. Т.о. комментарии ни как не влияют на порядок выполнения кода и вы их пишите для себя и тех кто через какое-то время может начать изучать ваш исходник. Комментарии могут использоваться в качестве инструмента отладки, т.е. вы можете разместить в комментарий кусок кода временно его исключив из выполнения и тем самым упростив момент поиска ошибки в другом участке. В Lua есть 2 вида комментариев.

Однострочный комментарий

Все написанное от последовательности символов «—» до конца строки считается комментарием.

Многострочный комментарий

Многострочный комментарий начинается последовательностью «—[[» и заканчивается через любое количество строк последовательностью «]]» Далее примеры применения комментариев:

Я не буду уделять излишнего внимания вопросу качества комментирования кода, это решает каждый сам для себя приведу лишь несколько простых советов:

  • Хороший код сам себя комментирует — т.е. если вы пишите очевидно и называете переменные обдуманно в большинстве случаев комментарии не требуются
  • Не пишите комментарии — для комментария. Т.е. не стоит писать комментарии там где и так все ясно.
  • Краткость — сестра таланта. Делайте комментарии простыми и понятными.
  • Комментируйте назначение файла и функций.
Илон Маск рекомендует:  Что такое код settype

Переменные, константы, область видимости

Большинство языков программирования имеют переменные. Под этим понятием в большинстве случаев понимается — поименованная, либо адресуемая иным способом область памяти, адрес или имя которой можно использовать для осуществления доступа к данным и изменять значение в ходе выполнения программы. В Lua переменные могут создавать прямо там где их нужно применять, т.е. нет определенного блока (как в языках типа Pascal) где необходимо заранее объявлять переменные перед тем как их использовать. Приведу пример объявления переменных:

Знатоки других языков думаю заметили несколько особенностей:

  • тип переменных не нужно указывать, значение определяет её тип
  • тип переменных можно менять, т.е. если переменная была численной (в примере «a»), а далее ей присвоили строчное значение она стала строчной
  • доступно параллельное присвоение через один знак «=» (переменные d,pi). Это свойство может значительно укоротить момент стартовой инициализации, так же позволяет выполнять обмен значений переменных без промежуточной переменной например так a,b = b,a
  • ключевое слово local. Это слово используется для того что бы ограничить область видимости переменных, если переменная объявлена локальной внутри операционного блока (функция, цикл, условный оператор) она будет видна только внутри него. Если де локальная переменная объявлена в глобальном контексте файла она будет видна с этой строки и до конца файла (подробней об области видимости вы узнаете в немного ниже)

Остановимся на константах. Под константой понимается — переменная значение которой не меняется в процессе использования. Часты бывает удобно некоторые значения многократно применяемы в проекте (например версия приложения) хранить в константах, в некоторых языках имеется инструмент создания констант в прямом смысле этого слова, т.е. переменных которые были единожды объявлены и в дальнейшем их значение невозможно изменить, в Lua такой инструмент отсутствует т.е. пенять можно все, (даже реализацию функции) и по этой причине удобным вариантом для защиты от смены констант можно считать — порядок их именования. Лучше всего константы именовать каким-то особым образом что бы в коде они были более заметными, например БОЛЬШИМИ_БУКВАМИ_СО_СЛОВАМИ_ЧЕРЕЗ_ПОДЧЕРКИВАНИЕ, но это не правило а скорее совет.

Кратно опишу формат допустимых имён переменных, констант и функций, некоторые вещи декларативны и их нельзя нарушать, другие просто советы:

  • переменные могут содержать латинские прописные и строчные буквы, цифры и символ подчеркивания «_»
  • переменные не могут начинаться с цифры
  • переменные не могут иметь имена зарезервированных слов: and, break, do, else, elseif, end, false, for, function, if, in, local, nil, not, or, repeat, return, then, true, until, while
  • зависимость от регистра. Как и в большинстве языков в Lua регистр является определяющим факторов в уникальности переменной, т.е. lua, LUA, lUa и LuA это все разные переменные.
  • не стоит злоупотреблять названием переменных начинающихся с символа нижнего подчеркивания, если конечно вы уверены что эти имена точно не используются языком для именования внутренних механизмов
  • используйте обдуманные имена переменных которые имеют широкую область видимости. Это стоит понимать так — если переменная используется в большой части проекта она не должна иметь имя ни чего не означающее и короткое
  • разделяете формат именования переменных, констант и функций. Например для констант уможно применять ТАКОЙ_ФОРМАТ, для переменный примерно_такой, а для функция использоватьТакойФормат — это сделает код более удобным.

Под областью видимости понимается — пространство кода в пределах которого можно непосредственно получить доступ к данным. Неверное понимание принципов организации области видимости может привести к массе неприятных ошибок, которые обычно трудно устранить:

  • переменную не видно — вам кажется что все хорошо, а переменная равна nil (не определена). Эту ошибку как правило легко выявить но не всегда легко устранить.
  • переменную видно там где она не используется — эта на первый взгляд мелкая проблема может привести к крайне сложным багам, например вы не ожидаете что переменная из другого участка кода будет видна в этой области и делаете поверку на ее несуществование (что бы ее инициализировать) и проверка не заканчивается успехом и ваш инициализирующий код не выполняется что приводит к использованию значения которое было определено в другом месте. Что бы избежать этой проблемы всегда и все переменные старайтесь делать минимально видимыми используя слово local. Использование глобальных переменных всегда нужно стараться сводить к минимуму

Далее мы не раз еще столкнемся с примерами неверной организации области видимости, я буду делать в этих местах акценты по этой причине этот раздел можно закончить.

Модули и организация проекта

Программный модуль — функционально законченный фрагмент программы, оформленный в виде отдельного файла с исходным кодом. Как вы уже знаете выполнение любого проекта в Corona SDK начинается с файла main.lua. Если писать всё приложение в одном файле у вас может возникнуть масса трудностей, приведу пример:

  • Большой объем кода. исходный текст почти любой полноценной игры может включать сотни, тысячи, десятки тысяч, а в некоторых случаях и более ста тысяч строк кода, если разместить весь код в одном файле на некотором этапе сопровождать этот проект станет просто невероятно сложно
  • Множество сцен. в большинстве случаев реальные приложения содержат более одной сцены (функционального экран), например различные меню, экраны загрузки, возможно несколько боевых сцен, сцены открытого мира и т.д. опять же если разместить все в один файл придется при переходе между сценами нагромождать код десятками процедур создания и удаления сцены, т.е. код опять же будет сильно усложняться
  • Универсальный переносимый код. В процессе создания своих прилодений вы часто будете сталкиваться с однотипными задачами, которые вы будете переносить в библиотеки, а далее эти библиотеки вы сможете легко переносить в ваши следующие проекты, если же писать все в одном файле вопрос о переносимости готовых библиотек будет весма затруднителен, так как полезный код придется вычленять фрагментами из огромного файла.



Возможны и другие проблемы если неверно организовать проект и писать все в один файл main.lua, но в наших уроках мы так делать не будем и далее я покажу тот способ который я выбрал для своих проектов и который не раз себя хорошо зарекомендовал, принимать его или придумывать свой — решать вам, но дальнейшие примеры проектов я буду оформлять таким способом. Таким образом мы пришли к заключению, что каким-то образом нам нужно разделать исходник проекта на несколько файлов, более того эти файлы будут иметь различное назначение и исходя из этого у каждого типа файлов будет свой порядок именования определяемые префиксом в имени. Этот способ лично мой и я не утверждаю что он лучший, но так как дальнейшие примеры игр которые вы увидите в моих статьях будут иметь такой механизм оформления проекта, я решил взять его за основу. Кратко пробежимся по типам файлов которые могут пригодится.

Сцена

Сцена — префикс sc. Формат имени файлов scName.lua. Где имя начинается с заглавной буквы и определяет назначение файла. Для остальных типов это правило так же будет действовать поэтому я буду указывать только их префиксы. Файл сцены имеет довольно строгий формат и он определяется требованиями библиотеки Corona SDK — composer. Рассмотрению этой библиотеки будет посвящен отдельный урок пока что прикладываю шаблон исходного файла:

Стоит отметить что файлы сцен не нужно каким-то образом подключать к проекту, так как их подключение будет производиться в рамках использования библиотеки composer.

Универсальная библиотека

Универсальная библиотека — префикс lib. В эти файлы нужно размещать готовые универсальные функции которые в дальнейшем можно будет применять в различных частях приложения, например тригонометрические функции ваших проектов можно разместить в файле libTriginom.lua а дальше эти функции будут пополняться и в следующих проектах их можно будет легко использовать просто переносом файла и подключением. Старайтесь избегать в универсальных библиотеках привязки к элементам графического дизайна приложения, а исходные значения передавайте параметрами вызова. Приведу пример простой библиотеки:

Эту библиотеку можно подключить поместив в main.lua следующий код:

Приведу пример использования функций в любой части проекта:

Виджет/сервис

Виджет/сервис — префикс svc. Виджет — аналог библиотеки, но основной функционал основан на создании графических компонентов. С помощью виджетов удобно создавать составной интерфейс, т.е. имеется основные статические компоненты сцены которые создаются в рамках основного кода в файлах sc и поверх статических компонентов могут создавать динамические виджеты в виде всплывающих окон, перемещаемых форм и прочих удобств. Удобней всего все виджеты проекта оформлять с единым интерфейсом(стандартным набором функций), например таким:

  • show() — создает окно с функционалом виджета и помещает его в заданном месте экрана
  • refresh() — обновляет состояние компонентов виджета делая его актуальным текущему моменту. Например если этот виджет является часами его необходимо обновлять раз в секунду или минуту (если нет секундной стрелки).
  • hide() — скрывает или удаляет весь интерфейс виджета

Стоит заметить что нет ни какого риска в том что у вас в различных виджетах одинаковые названия методов (функций) — show/refresh/hide для доступа к функции необходимо добавление имени виджета (как и в случае с библиотеками) и по этой причине глобально пространство имен не будет засорено.

Приведу пример виджета (часы):

порядок подключения и применения сервиса следующий:

сервисы как и библиотеки стоит делать достаточно универсальными так как они то же кандидаты на повторное использование, большую часть параметров (в идеальном случае все) нужно делать не обязательными, т.е. имеющими значения по умолчанию.

Базы данных

Базы данных — префикс db. Эти файлы не содержат функций но хранят сведения о статических настройках объектов системы, например характеристики юнитов. Приведу пример базы данных с настройками юнитов:

стоит отметить что подобный тип реализации для более крупных баз бывает проще заменить на такую реализацию

Фактически это одно и то же просто в первом случае все инициализируется сразу, а во втором случае при подключении библиотеки выполняется цикл заполняющий точно такую же таблицу, второй способ более универсален так как позволяет во-первых в будущем более удобно редактировать эти данные, во-вторых если данных много позволяет значительно сократить запись. Подключать использовать такие базы данных необходимо следующим образом:

Вставка кода

Вставка кода — префикс ins. Как бы мы не пытались сократить размер файлов не всегда это возможно, в этом случае можно некоторые объединенный общей целью участки вынести в отдельный файл. Приведу пример, имеется код:

теперь вынесем функции sum и razn в отдельный файл InsExample.lua имеем 2 файла:

Стоит обратить внимание, что при переносе в отдельный файл я сделал функции глобальными (убрал local), в противном случае они выйдут из области видимости main.lua. Так же нужно понимать что внутри файл insExample.lua не будет видна локальная переменная Р, но будет видна глобальная переменная k, а если объявить переменную k после require то и она не будет видна.

ВАЖНО: При любом варианте использования require для любых манипуляций с файлами этот вызов выполняется только один раз при первом проходе нити выполнения через этот участок кода, это нужно всегда учитывать если не хотите долго мучиться со сложными багами. Так же если вы будете как и я в модулях типа db/lib/svc использовать некую переменную M для сборки данных перед return (или любую другую) не забывайте делать эту переменную локальной, так как в противном случае каждый следующий require будет переписывать результат предыдущего и это будет приводить к еще более сложной ошибке.

Илон Маск рекомендует:  Оформление ссылок

Условные операторы

Как в большинстве других языков в Lua есть возможность создания операций условного ветвления кода, для этих целей используется несколько видов записи оператора if и достаточно удобный тернарный способ ветвления.

Для сравнения данных используются операции сравнения. Каждая такая операция состоит из двух переменных, между которым стоит оператор сравнения, всего их в Lua имеется 6:


= не равно

  • больше
  • = больше или равно
  • В сущности результатом любой операции сравнения является false или true (ложь или правда), эти значения характерны для типа ,boolean который наряду с другими типами будет рассмотрен ниже. Теперь рассмотрим с помощью каких конструкций языка применяются операции сравнения.

    Оператор IF

    Сразу к примеру — если a больше b, присваиваем cзначение true

    Как видите порядок применения довольно простой. Но как обычно есть тонкости — содержимое блока if является операционным блоком т.е. областью ограничения локальной видимости, т.о. если переменную c сделать локальной она не будет видна после end, естественно выход есть если нам нужна локальная переменная c видна за блоком If ее нужно объявить перед if:

    Как я говорил выше имеется тернарный способ организации ветвления и описанный выше код можно легко записать этим способом

    Вот так просто:) Теперь пару слов о том как сделать более сложное условие в if. Имеются логические операторы and(и) и or(или). Они работает примерно так же как и в большинстве языков, хотя есть и свои особенности.

    Условия совмещенные операторами and должны выполниться все, условия выполняются слева направо если в процессе выполнения проверок не выполнилось одно условие, следующие проверки не будут проводиться. Это весьма важный момент и его нужно четко понимать, так как это можно использовать как в своих целях так и иметь из-за этой особенности массу сложных багов, приведу пример полезного использования. Имеется объект находящийся скажем на третей глубине вложения в другие объекты ну скажем такой obj1.obj2.obj3 мы хотим сделать проверку на его существование, и на первый взгяд можно сделать так:

    вам может показаться что это хорошая идея, но на самом деле это не так, допустим не существует объект obj1 или obj2 и в этом случае возникнет ошибка т.е. проверку нужно делать так:

    Теперь проверка будет выполнения безопасно и без ошибок. Достаточно похожий механизм и при реализации тернарным оператором

    Если выполнилось хотя бы одно условие разделенное оператором or дальнейшая проверка останавливается условие считается верным. Т.е. этот оператор работает по принципу схожему с and, но с другими требованиями, для and они — абсолютны, для or — минимальны. Приведу пример типичного сравнения с применением оператора or.

    полностью аналогична тернарная реализация:

    Логическая операция отрицания. Условие перед которым стоит not понимается наоборот, т.е. если a > b это понимается как a больше b, то not a > b понимается как a НЕ больше b.

    IF ELSE

    Часто возникает необходимость в следующем виде ветвления: если выполнилось условие делаем действие, в противном случае другое действие. Это реализуется оператором if else и реализация выглядит следующим образом:

    Как видите ни чего сложного. Тернарная реализация этого примера будет иметь как оператор AND так и оператор OR:

    IF ELSEIF ELSE

    Имеется еще один вариант условия: если выполнено условие1 делаем — действе1, если условие2 делаем — действеи2… если условиеN делаем — действиеN, в противном случае действиеX. Во многих языках этот тип ветвления реализован средствами специальных операторов множественного ветвления вроде switch, в Lua этого нет есть свой способ:

    Как видите — все просто. Есть особенности в порядке выполнения составного оператора IF ELSEIF ELSE: во-первых else — не обязателен, во-вторых если произошло первое вхождение в условие, то дальнейшие проверки не выполняются, а происходит переход на строчку следующую за закрывающим end. Может показаться что досрочный выход из составного оператора не имеет значения и это не может вызвать ошибок, но это не так, приведу пример который показывает что неверное понимание этого принципа может дать неожидаемый результат:

    Результат выполнения этого действия будет только один print -> 2. В заключении покажу как реализовать тернарным оператором первый пример использования IF ELSEIF ELSE:

    Обратите внимание на то что or имеет больший приоритет нежели and просто исходя из его функциональности, по это причине блоки с or были помещены в скобки, что сделало из них один оператор.

    ВАЖНО: В этой главе я показал как использовать тернарное присвоение и скорее всего это показалось вам весьма заманчивым и простым способом организации кода, хочется сделать небольшие пояснения по поводу порядка использования этого механизма: во-первых — применяете тернарный оператор только там где это не сделать код менее читаемым, во-вторых на первых порах использования этого способа внимательно отлаживайте эти строки так как не всегда получается с первого раза написать верно.

    QUIKBOT . EVOLUTION …

    Свежие записи


    Архивы

    Свежие комментарии

    Переменные, массивы и функции в QLua (lua)

    В Qlua есть следующие типы переменных:

    nil (неопределенный),
    boolean (логический),
    number (числовой),
    string (строковый),
    function (функция в Lua является типом данных),

    а также, есть массивы (таблицы Lua), в т.ч. многомерные, которые могут содержать в себе все вышеперечисленные типы данных.

    Для того, чтобы объявить переменную в Qlua, достаточно присвоить ей значение. Язык Qlua сам определит к какому типу отнести переменную.

    Все переменные, объявленные выше, являются ГЛОБАЛЬНЫМИ по типу видимости, т.е., объявив так переменную в одной функции, можно будет использовать ее значение в любой другой функции, находящейся в том же скрипте. Можно объявить переменную ЛОКАЛЬНОГО типа, использовать которую можно будет только внутри той функции, в которой Вы ее создали. Для этого перед именем переменной нужно поставить идентификатор local.

    Функции

    QLua поддерживает параллельное присваивание:

    Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей .

    Добавить комментарий Отменить ответ

    Для отправки комментария вам необходимо авторизоваться.

    Переменные, массивы и функции в QLua (lua): 158 комментариев

    добрый вечер!
    нуждаюсь в помощи.
    пишу индикатор.
    Settings=
    <
    Name = «xerman»,
    period=4,
    line=
    <
    <
    Name = «High»,
    Type =TYPE_LINE,
    W > Color = RGB(120,90, 140)
    >,
    <
    Name = «Low»,
    Type =TYPE_LINE,
    W > Color = RGB(120,90,140)
    >
    >
    >

    function Init()
    return 2
    end
    function OnCalculate(index)
    local induc=0
    local vxod=60
    local diap=math.abs(C(index)-C(index-1))
    t=<>
    t[#t+1]= diap
    Period = Settings.period
    if #t

    return nil
    else
    local sum=0
    for i=#t-Period+1, #t do
    sum=sum+diap
    end
    induc=sum/Period
    end
    return induc, vxod
    end

    мне нужно посчитать среднее значение нескольких последних разниц цен закрытия. не понимаю синтаксис языка. в общей сложности 10 часов провел переписывая код, вставляя в график и получая шлямбуром по подбородку.
    я так понимаю у меня есть переменная diap и когда я просто пишу return diap, то индикатор строится и показывает мне значения разниц, а вот как среднюю то от них взять.
    я догадываюсь что надо создать массив в который эта переменная diap будет наполняться новыми значениями, но как это реализовать хоть убейте не пойму.
    помогите пожалуйста, умоляю.

    Объявление глобальной переменной внутри функции в LUA

    У меня есть функция, внутри которой я объявлял глобальную переменную obs , внутри функции и присваивал некоторое значение. Если я хочу получить доступ к этому в каком-то другом файле lua, это дает ошибку: «попытаться вызвать obs no n value, что мне делать нужно сделать, чтобы иметь возможность получить к нему доступ?

    Вот фиктивный код для него

    Есть несколько способов сделать это. С вашей текущей настройкой вы можете сделать следующее:

    Заполнение вещей в глобальной таблице, как правило, является ужасной идеей, хотя, поскольку любой скрипт где-либо еще может потенциально перезаписать значение, нуль из переменной и т.д., Намного лучший способ imo состоял бы в том, чтобы ваш a.lua возвращал свою функциональность в таблицу которые вы можете захватить в файлах, которые этого требуют. это позволит вам определить функцию геттера, чтобы вернуть переменную «obs», прикрепленную непосредственно к вашей функции «a.lua» в ее текущем состоянии.

    вы, вероятно, захотите сделать что-то подобное для лучшей переносимости (также гораздо яснее, какие модули определяют, какие функции таким образом):

    поскольку вы упомянули, что не можете использовать require, я предполагаю, что вы работаете в другой структуре, которая использует некоторую другую функцию для загрузки библиотек/файлов. в этом случае вам, вероятно, придется просто набрать все в глобальной таблице. может быть, что-то вроде этого:

    Помните, что некоторые программы Lua внутри других программ (Garry Mod, World of Warcraft, Vera, Domoticz) используют _ENV вместо _G, чтобы ограничить их объем. Таким образом, глобальные переменные должны быть:

    Причина, по которой это происходит, заключается в том, что разработчик хочет ограничить стандартную библиотеку Lua, чтобы избежать доступа к таким методам доступа: os.exit().

    Чтобы увидеть, используется ли _ENV вместо _G, распечатайте его, и если он вернет таблицу вместо nil, она, скорее всего, будет использоваться. Вы также можете протестировать следующий фрагмент:

    Там, где нужно напечатать true, вы используете.

    Вопрос по lua &#8211 как назначить переменную lua по ссылке

    Как я могу назначить переменную по ссылке в Lua другой?

    Например: хотите сделать эквивалент & quot; a = b & quot; где а будет указатель на б

    Фон: есть случай, когда у меня есть что-то вроде этого:

    PS. Например, ниже показано, что b = a является значением. ПРИМЕЧАНИЕ. Я использую Corona SDK.

    что переменные являются просто именами для значений. Но вы можете вычислить имена переменных, если вы имеете дело с ключами в таблице. Это означает, что вы можете использовать имена ключей для выполнения вашей условной логики.

    в отношении вашего поясненного поста и примера, в Lua нет такой вещи, как тип ссылки, который вы хотите. Вы хотите, чтобы переменная ссылалась на другую переменную. В Lua переменные — это просто имена для значений. Вот и все.

    Следующее работает, потому что b = a оставляет оба a а также b ссылаясь на то же значение таблицы:

    Вы можете думать обо всех переменных назначений в Lua как по ссылке.

    Технически это верно для таблиц, функций, сопрограмм и строк. Этоmay as well будьте верны с числами, логическими значениями и нулем, потому что они являются неизменяемыми типами, поэтому для вашей программы разницы нет.

    Краткая версия: это имеет практическое значение только для изменчивых типов, которые в Lua — это userdata и table. В обоих случаях присвоение копирует ссылку, а не значение (то есть не клон или копию объекта, а присвоение указателя).

    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL