Контакти

Вступ до Lua. Хочу знати все. Мова Lua Навчання lua з нуля

Нещодавно мій близький друг ходив на співбесіду з влаштування на роботу до місцевої організації розробки ігор. Я не збираюся тут називати імена, скажу тільки, що це був свого роду великий бутік Розробка Ігор у Ванкувері. Він не отримав роботи, але сьогодні не про нього. Особисто я вважаю, що одна з причин була через його недостатньо дружні стосунки зі скриптом, який вони використовують.

Вступ

Я займаюся цією областю, тому що навчаю студентів програмування ігор, але саме цій темі я приділив мало уваги в минулому. Ми охоплюємо Unreal Script як частину курсу "Використання існуючих". Але ми практично не розглядали скрипт-движок, як частина утиліт або частина двигуна. Так, озброївшись веб-сайтом, я вирішив зламати цей невеликий бар'єр. Результат описано у цьому документі.

Єдине, я не впевнений, наскільки більшим буде цей документ. Я можу розбити його на кілька невеликих частин або опублікувати повністю довгою тирадою від початку до кінця. Так чи інакше, я вирішу це трохи пізніше, коли оформлю свої записи більш осмислений і послідовний формат.

Чому і чому ні?

Насамперед, навіщо використовувати скрипт-мову? Більшість ігрової логіки може бути описана на скрипт-мові для різних цілей, замість програмувати її як частина ігрового движка. Наприклад, завантаження або ініціалізації рівня. Після завантаження рівня, можливо Ви захочете перевести сцену до ігрового плану або можливо захочете показати деякий попередній текст. Використовуючи скрипт-систему, Ви можете змусити деякі об'єкти гри виконувати певні завдання. Також, подумайте про реалізацію штучного інтелекту. Чи не Ігрові Персонажі повинні знати, що робити. Програмування кожного NPC "вручну", в тілі ігрового двигуна зайве ускладнить завдання. Коли ви захочете змінити поведінку NPC, вам доведеться перекомпілювати ваш проект. З скрипт-системою, Ви можете робити це в інтерактивному режимі, змінюючи поведінку та зберігаючи налаштування.

Я трохи торкнувся цієї проблеми в останньому параграфі, ми ще поговоримо про це трохи пізніше. Питання чому б не написати логіку виключно на C/C++? Простіше кажучи, що в перспективі у програміста те, що все лягає безпосередньо на нього і почне він відповідно з ігрового коду, заразом доведеться писати і двигун і утиліти і т.д. Але ми тепер можемо з простою скриптом перекласти деякі завдання функціональних можливостей на дизайнерів рівнів. Вони можуть почати возитися з рівнем та оптимізувати геймплей. Ось власне приклад:

Давайте уявимо, що Джо, наш нещасний програміст, пише весь ігровий движок, інструменти та логіку гри сам. Так, Джо доведеться туго, але давайте припустимо, що йому все байдуже. У нас також є Брендон, ігровий дизайнер. Брендон досить розвинений хлопчина з розкішними ідеями щодо гри. І так, наш кодер Джо, повзає і здійснює всю ігрову логіку використовуючи інструментарій, який він розробив, ґрунтуючись на початковому проекті Брендона. Все добре у конторці. Перший етап закінчено і Джо з Брендоном сидять у залі засідань та перевіряють свої чималі праці. Брендон помічає кілька проблем у геймплеї, який поводиться неналежним чином. Отже, Джо повертається до коду і робить необхідні зміни. Цей процес може зайняти день, принаймні якщо це не тривіальна зміна. Потім ще день для перекомпілювання проекту. Щоб не втрачати зайву добу, більшість контор залишають процес складання на ніч. Так, як ми бачимо проходить 24 години, перш ніж Брендон побачить зміни, які він вимагав.

Тепер, давайте уявимо, що наш головний герой Джо вирішив, що реалізація ігрової логіки використовує скрипт-рух в його інтересах. Це займе спочатку деякий час, але він відчуває, що в кінцевому рахунку це принесе користь. І так, він перекладає з ігрового двигуна деякі функціональні можливості на скрипт-систему гри. Він також пише всю ігрову логіку у згаданій раніше скрипт-системі. І так, коли він зустрічається з Брендоном і дизайнер помічає щось, що не відповідає його задуму, Джо швиденько відкриває консоль, робить деякі зміни в скрипті, перезапускає гру і вже бачить нову поведінку. Зміни можуть бути одразу внесені та показані негайно, замість того, щоб чекати на рекомпілінг. І якщо Джо був особливо виразний, скрипт-система могла бути використана для утиліт і доступна для левел-дизайнерів при побудові рівнів. Якщо рухатися таким шляхом, то при невеликому навчанні проектувальники рівнів могли б самі встановлювати ігрові події, такі як тригери, двері, інші ігрові події і радіти життю не напружуючи програміста.

Це досить надуманий приклад і може бути трохи перебільшеним, але я сподіваюся, що він покаже різницю між підходами. Отже, спробуємо зробити з такою моделлю, що означає рух до більшої кількості автоматично керованих даних. Так, по суті, куди ми рухаємось:

  1. Кодер зацікавлений у написанні коду движка/інструментів, а не логіки гри.
  2. Час був витрачений на написання движка/інструментів гри.
  3. Дизайнерам подобається "балуватися" з речами. Скриптинг відкриває їм свободу у проектуванні рівнів та функціональних можливостей. Це також додає їм більше гнучкості, щоб експериментувати з речами, для яких вони зазвичай залучали програміста.
  4. Ви не повинні перекомпілювати, якщо хочете змінити функціональні можливості гри. Просто змініть скрипт.
  5. Ви хочете зруйнувати зв'язок між машинним та ігровим кодом. Вони мають бути двома окремими частинами. Таким чином, буде зручно використовувати двигун для наступних сіквелів (я сподіваюся).

Тут я зроблю кілька прогнозів. Протягом 5 років, дизайнери рівнів повинні робити більше, ніж просто будувати рівні. Вони повинні бути здатними використовувати сценарій для ігрових сцен. Декілька компаній з передовими поглядами вже застосували цей підхід. Також, Ви можете побачити цей спосіб інтеграції в редакторах як UnrealEd і Aurora toolset Bioware.

Роз'яснення та розголошення

Сподіваюся, зараз Ви вже купилися на мої слова і захотіли включити скрипт-компонент у вашу гру. І так, наступне питання: як, чорт забирай, Ви це робите?

Що я збираюся використовувати для мого скрипт-компонента - це впроваджуваний скрипт-движок Lua. На початку скажу, що я не фахівець у Lua, але це відносно проста мова і не вимагатиме втомливого вивчення для оволодіння ним. Деякі наступні приклади, якими я пробігатимуся, досить прості. Наприкінці цього документа я збираюся включити деякий додатковий довідковий матеріал. По справедливості, є інші скрипт-мови, типу Small, Simkin, Python, Perl. Однак Lua приємна і чиста мова. Це справді гарна перевага.

Lua має відкритий вихідний код. Це добре, тому що: (a) Ви отримуєте вихідники мови і можете ритися в них скільки заманеться, (b) вона безкоштовна. Ви можете використовувати його в комерційних програмах, і не розкидатися грошима. Ну, а для некомерційних проектів самі розумієте безкоштовно == добре.

Так, хто зараз використовує Lua? Lua написаний шарашкіною конторкою і його використовують лише бідні? Ммм... не зовсім так. Lua з'явився не вчора та використовувався досить відомими особистостями:

  • Lucasarts
    • Grim Fandango
    • Escape from Monkey Island
  • Bioware
    • Neverwinter Nights

Ок, досить з будь-хто з lua розробників. Ви можете це побачити на вебсайті lua.

Давайте почнемо з справді простого. Перша річ, яку ми маємо побудувати, покаже нам, як використовується lua інтерпретатор. Що для цього потрібно:

  1. Отримання коду інтерпретатора Lua.
  2. Налаштування середовища розробки.
  3. Складання інтерпретатора з нуля.

Гей, я подумав, Ви сказали досить розголосу?

Ну, що, досить? Тож давайте перейдемо до справи. Ви можете отримати весь вихідний код Lua на офіційному сайті. Я також хотів би взяти секунду і звернути увагу, що на горизонті є нова версія lua 5.0. Я не збираюся обговорювати цю версію у цій статті. Я розберуся з нею пізніше, а поки що ми будемо використовувати 4.0.1.

Перша річ, яку ми зробимо – зберемо бібліотеку lua. Таким чином, нам не потрібно включати вихідні джерела кожного разу при складанні проекту. Це не складно, і це не мета наших уроків. Тому я заздалегідь увімкнув бібліотеку як частину цієї статті. Я використав статичну бібліотеку для цього прикладу. Так, можливо, я зібрав би її як DLL, але для скрипт-системи статична бібліотека працює трохи швидше. Зауважте, не багато, але швидше.

Наш сьогоднішній гість – справжній боєць прихованого фронту. Ви могли бачити його в іграх (World of Warcraft, Angry Birds, X-Plane, S.T.A.L.K.E.R.) або продуктах компанії Adobe (Lightroom), але навіть не замислювалися про його існування. Тим часом цій мові вже майже 25 років і весь цей час він непомітно робив наше віртуальне життя трохи кращим.

Коротка довідка

Lua був би придуманий в 1993 році в Католицькому університеті Ріо-де-Жанейро. Назва перекладається з португальської, як Місяць, причому творці переконливо просять не писати LUA, щоб, не дай Боже, хтось не прийняв назву за абревіатуру. Є мультипарадигмальною скриптовою мовою, яка використовує прототипну модель ООП.

Типізація тут динамічна, а для успадкування використовуються метатаблиці, тобто це чудовий інструмент для розширення можливостей вашого продукту. Причому через компактність він придатний для використання практично на будь-якій платформі. Посудіть самі: tarball Lua 5.3.4 важить всього 296 кілобайт (у "розтисненому" вигляді - 1.1 мегабайт), інтерпретатор (написаний на C) для Linux - від 182 до 246 кілобайт, а стандартний набір бібліотек - ще 421 кілобайт.

Код

На вигляд, та й можливостям Lua схожий на чергову спробу переробити JavaScript, якби не той факт, що останній з'явився на два роки пізніше. Дивіться самі:

Почнемо з традиційного:

print("Hello World")

Погодьтеся, знайоме і не надто інформативно. Цікавіший приклад з погляду знайомства з Lua - обчислення факторіалу введеного числа:

Function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end

Print("enter a number:")
a = io.read("*number") - read a number
print(fact(a))

Все цілком зрозуміло. До речі, у Lua підтримується паралельне присвоєння:

І на закінчення досить простий приклад з використанням бібліотек:

#include
#include
#include
#include
#include

Int main (void) (
char buff;
int error;
lua_State * L = lua_open(); /* opens Lua */
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */

While (fgets(buff, sizeof(buff), stdin) != NULL) (
error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
lua_pcall (L, 0, 0, 0);
if (error) (
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop (L, 1); /* pop error message from the stack */
}
}

Lua_close(L);
return 0;
}

Переваги і недоліки

Отже, чим же гарний Lua?

По-перше, як уже було зазначено, своєю компактністю, а разом з тим, що вихідники написані на С, ви отримуєте повну взаємодію з однією з найпопулярніших мов на планеті та широкий спектр доступних платформ.

Середовища розробки

LDT (Lua Development Tools) для Eclipse – розширення для однієї з найпопулярніших IDE;

ZeroBrane Studio – спеціалізоване середовище, написане на Lua;

Decoda - не найпопулярніша кросплатформова IDE, але як альтернатива підійде;

SciTE - хороший редактор, що повноцінно підтримує Lua;

WoWUIDesigner - вгадайте, для якої гри це середовище допомагає обробляти скрипти, зокрема Lua?

Корисні посилання

http://www.lua.org/home.html - офіційний сайт з усією необхідною інформацією, підручником, книгами, документацією та навіть є трохи специфічного гумору;

http://tylerneylon.com/a/learn-lua/ - відмінне навчання від Tyler Neylon. Підійде програмістам із досвідом, хто добре знає англійську мову (втім, зі словником теж не виникне великих проблем) і просто бажає розширити свій світогляд;

https://zserge.wordpress.com/2012/02/23/lua-за-60-хвилин/ - основи Lua за 60 хвилин від явно небайдужої до цієї мови програміста. Російською мовою;

http://lua-users.org/wiki/LuaTutorial - вікі-підручник;

https://youtube.com/watch?v=yI41OL0-DWM- відеоуроки на YouTube, які допоможуть вам розібратися з налаштуванням IDE і базовими принципами мови.

Скрипти мовою Lua

Написаний на Lua скрипт не має якоїсь спеціальної функції, з якої починалося б його виконання. Скрипт можна розглядати як набір команд (інструкцій), який виконується, починаючи з першої інструкції.

Скрипт може бути дуже простим, що складається всього з однієї команди, так і дуже складним, що містить десятки, сотні і навіть тисячі інструкцій. Наступні один за одним інструкції можуть розділятися крапкою з комою (;). Однак ця вимога не є обов'язковою, тому весь наведений нижче код є коректним з погляду синтаксису:

Робота зі змінними в Lua

Змінні використовують для зберігання значень у процесі виконання скрипта.

Імена змінних у Lua

Іменами (ідентифікаторами) змінних Lua можуть бути будь-які послідовності з букв, цифр і символу підкреслення, що починаються не з цифри.

Зверніть увагу

Мова Lua розрізняє регістр символів, тому abc, Abc, ABC є різними іменами.

У наведеній нижче таблиці наведено слова, які зарезервовані мовою Lua і не можуть використовуватися в іменах змінних:

and break do else elseif

end false for function if

in local nil not or

repeat return then true until

Крім того, всі імена, що починаються з символу підкреслення, за яким йдуть великі літери (наприклад, _VERSION), також є зарезервованими.

Які змінні бувають у Lua?

Змінні в Lua можуть бути глобальними та локальними. Якщо змінна не оголошена як локальна, вона вважається глобальної.

Глобальні змінні Lua

Глобальна змінна утворюється у момент привласнення їй першого значення. До надання першого значення звернення до глобальної змінної дає nil.

MsgBox(tostring(g)) --> nil

MsgBox(tostring (g)) --> 1

Глобальна змінна існує до тих пір, поки існує середовище виконання скрипта і доступна будь-якому Lua-коду, що виконується в цьому середовищі.

При необхідності видалити глобальну змінну можна явно, просто надавши їй значення nil.

g = 1 - створюємо глобальну змінну g зі значенням 1

g = nil - видаляємо глобальну змінну g

MsgBox(tostring(g)) --> nil

Усі глобальні змінні є полями звичайної таблиці, яка називається глобальним оточенням. Ця таблиця доступна через глобальну змінну _G. Оскільки полями глобального оточення є всі глобальні змінні (включаючи _G), то _G._G == _G.

Локальні змінні Lua

Будь-які локальні змінні повинні бути оголошені з використанням ключового слова local. Оголосити локальну змінну можна будь-де скрипта. Оголошення може включати присвоювання змінної початкового значення. Якщо значення не надано, змінна містить nil.

local a - оголошуємо локальну змінну a

local b = 1 - оголошуємо локальну змінну b, надаємо їй значення 1

local c, d = 2, 3 - оголошуємо локальні змінні c і d, надають їм значення 2 і 3

Область видимості локальної змінної починається після оголошення і продовжується до кінця блоку.

Примітка

Областью видимості змінної називається ділянка коду програми, у якого можна отримати доступом до значення, що зберігається у цій змінної.

Під блоком розуміється:

тіло керуючої конструкції (if-then, else, for, while, repeat);

тіло функції;

фрагмент коду, що міститься у ключових словах do...end.

Якщо локальна змінна визначена поза будь-яким блоком, її область видимості поширюється остаточно скрипта.

local i = 1 – змінна i локальна в межах скрипту

while i<= a do - цикл от 1 до 5

local a = i^2 - змінна а локальна всередині циклу while

MsgBox(a) --> 1, 4, 9, 16, 25

MsgBox(a) -->

if i > 5 then

local a - змінна а локальна всередині then

MsgBox(a) --> 10

MsgBox(a) --> 5 (тут звернення до глобальної a)

local a = 20 – змінна а локальна всередині do-end

MsgBox(a) --> 20

MsgBox(a) --> 5 (тут звернення до глобальної a)

Зверніть увагу

Якщо можливо, рекомендується використовувати локальні змінні замість глобальних. Це дозволить уникнути «засмічення» глобального простору імен та забезпечить кращу продуктивність (оскільки доступ до локальних змінних у Lua виконується дещо швидше, ніж до глобальних).

Типи даних Lua

Які типи даних підтримує мова Lua?

Lua підтримує такі типи даних:

1. Nil (нічого). Відповідає відсутності змінної значення. Цей тип представлений єдиним значенням – nil.

2. Boolean (логічний). До цього типу відносяться значення false (брехня) та true (істина).

При виконанні логічних операцій значення nil сприймається як false. Всі інші значення, включаючи число 0 та порожній рядок, розглядаються як true.

3. Number (числовий). Служить уявлення числових значень.

У числових константах можна вказувати необов'язкову дробову частину та необов'язковий десятковий порядок, що задається символами "e" або "E". Цілочисленні числові константи можна задавати в шістнадцятковій системі, використовуючи префікс 0x.

Приклади допустимих числових констант: 3, 3.0, 3.1415926, 314.16e-2, 0xff.

4. String (рядковий). Для представлення рядків.

Строкові значення задаються як послідовність символів, укладеної в одинарні або подвійні лапки:

a = «це рядок»

b = "це другий рядок"

Рядки, укладені в подвійні лапки, можуть інтерпретувати C-подібні послідовності, що управляють (escape-послідовності), що починаються з символу «\» (зворотний слеш):

\b (пробіл),

\n (переклад рядка),

(повернення каретки);

\t (горизонтальна табуляція),

(зворотний сліш);

"" (подвійна лапка);

(одинарна лапка).

Зверніть увагу

Символ у рядку також може бути представлений своїм кодом за допомогою escape-послідовності:

де ddd - послідовність не більше трьох цифр.

Крім лапок для визначення рядка можуть також використовуватися подвійні квадратні дужки:

Визначення рядка за допомогою подвійних квадратних дужок дозволяє ігнорувати всі escape-послідовності, тобто рядок створюється повністю так, як описано:

local a = [] у Lua]=]

Буде терміну: «визначення рядка [] у Lua»

5. Function (функція). Функції Lua можуть бути записані в змінні, передані як параметри в інші функції і повернуті як результат виконання функцій.

6. Table (таблиця). Таблиця є набір пар «ключ» - «значення», які називають полями або елементами таблиці. Як ключі, і значення полів таблиці може мати будь-який тип, крім nil. Таблиці немає фіксованого розміру: у час у яких можна додати довільне число елементів.

Докладніше - у статті «Створення таблиць у Lua»

7. Userdata (Дані користувача). Є спеціальним типом даних. Значення цього не можуть бути створені або змінені безпосередньо в Lua-скрипті.

Userdata використовується для представлення нових типів, створених у програмі, що викликає, або в бібліотеках, написаних мовою С. Наприклад, бібліотеки розширень Lua для «CronosPRO» використовують цей тип для представлення таких об'єктів, як:

банки даних (клас Bank);

бази даних (клас Base);

записи (клас Record) тощо.

8. Thread (потік). Відповідає потоку виконання. Ці потоки жодним чином не пов'язані з операційною системою та підтримуються виключно засобами самого Lua.

Як у Lua задати тип змінної?

Lua не передбачає явного завдання типу змінної. Тип змінної встановлюється на момент присвоєння змінної значення. Будь-який змінної то, можливо присвоєно значення будь-якого типу (незалежно від цього, значення якого типу вона містила раніше).

a = 123 – змінна a має тип number

a = «123» – тепер змінна a має тип string

a = true – тепер змінна a має тип boolean

a = () – тепер змінна a має тип table

Зверніть увагу

Змінні типу table, function, thread та userdata не містять самих даних, а зберігають посилання на відповідні об'єкти. При привласненні, передачі в функцію як аргумент і повернення з функції як результат копіювання об'єктів не відбувається, копіюються лише посилання на них.

a = () – створюємо таблицю. У змінну a міститься посилання таблицю

b = a - змінна b посилається ту саму таблицю, як і a

a = 10 - елемент таблиці з індексом 1 присвоєно значення 10

MsgBox(b) --> "10"

MsgBox(a) --> "20"

Інші дані є безпосередніми значеннями.

MsgBox(a) --> "20"

MsgBox(b) --> "10"

Як у Lua отримати тип змінної?

Тип значення, збереженого в змінній, можна дізнатися за допомогою стандартної функції типу. Ця функція повертає рядок, що містить назву типу ("nil", "number", "string", "boolean", "table", "function", "thread", "userdata").

t = type ("це рядок") - t дорівнює "string"

t = type (123) - t дорівнює "number"

t = type (type) - t дорівнює "function"

t = type (true) - t дорівнює "boolean"

t = type (nil) - t дорівнює "nil"

t = type (CroApp.GetBank()) - t одно "userdata"

Як у Lua перетворити тип змінної?

Lua за потреби автоматично перетворює числа на рядки і навпаки. Наприклад, якщо рядкове значення є операндом в арифметичній операції, воно перетворюється на число. Аналогічно числове значення, що зустрілося там, де очікується рядкове, буде перетворено на рядок.

a = "10" + 2 - a дорівнює 12

a = "10" + 2 - a дорівнює "10 + 2"

a = "-5.3e-10"*"2" - a дорівнює -1.06e-09

a = «рядок» + 2 – Помилка! Неможливо перетворити «рядок» на число

Значення будь-якого типу можна явно перетворити на рядок за допомогою стандартної функції tostring.

a = tostring (10) - a дорівнює «10»

a = tostring (true) - a одно "true"

a = tostring (nil) - a так само «nil»

a = tostring (( = "це поле 1")) - a одно "table: 06DB1058"

З попереднього прикладу видно, що вміст таблиць функцією доstring не перетворюється. Виконати це перетворення можна за допомогою функції render.

a = render (10) – a дорівнює «10»

a = render (true) - a одно "true"

a = render (nil) - a так само «nil»

a = render (( = «це поле 1»)) - a одно "( = «це поле 1»)"

Для явного перетворення значення число можна використовувати стандартну функцію tonumber. Якщо значення є рядком, який можна перетворити на число (або вже є числом), функція повертає результат перетворення, інакше повертає nil.

a = tonumber ("10") - a дорівнює "10"

a = tonumber («10»..".5") - a одно 10.5

a = tonumber (true) - a дорівнює "nil"

a = tonumber (nil) - a так само «nil»

Розміщення коментарів у Lua

Коментар в Lua починається двома знаками "мінус" (--) і продовжується до кінця рядка.

local a = 1 - однорядковий коментар

Якщо безпосередньо після символів «--» йдуть дві квадратні дужки, що відкривають ([[), коментар є багаторядковим і триває до двох закриваючих квадратних дужок (]]).

local a = 1 - [[ багаторядковий

коментар ]]

Подвійні дужки у коментарях можуть бути вкладеними. Для того, щоб їх не переплутати, між дужками вставляється знак рівності (=):

local a = [[Компанія «Кронос»]] - [=[

local a = [[Компанія «Кронос»]]

Кількість символів "=" визначає вкладеність:

local a = [=[визначення деякого рядка [] у мові Lua]=] --[==[

local a = [=[визначення деякого рядка [] у мові Lua]=]

Операції, що застосовуються у Lua

У виразах, написаних на Lua, можна застосовувати такі види операцій:

1. Арифметичні операції.

Lua підтримує такі арифметичні операції:

+ (Додаток);

- (віднімання);

* (множення);

/ (Поділ);

^ (зведення на ступінь);

% (залишок від ділення).

Зверніть увагу

Арифметичні операції застосовні як до числа, так і рядків, які в цьому випадку перетворюються на числа.

2. Операції порівняння.

У Lua допустимі наступні операції порівняння величин:

== (Рівно);

~= (не дорівнює);

< (меньше);

> (більше);

<= (меньше или равно);

>= (більше чи одно).

Зверніть увагу

Операції порівняння завжди повертають логічне значення true чи false.

Правила перетворення чисел у рядки (і навпаки) при порівняннях не працюють, тобто вираз "0" == 0 дає в результаті false.

3. Логічні операції.

До логічних операцій належать:

and (логічне І).

Операція and повертає свій перший операнд, якщо вона має значення false або nil. Інакше операція повертає другий операнд (причому цей операнд може бути довільного типу).

a = (nil and 5) - a дорівнює nil

a == (false and 5) - a дорівнює false

a == (4 and 5) - a дорівнює 5

or (логічне АБО).

Операція or повертає перший операнд, якщо він не false і не nil, інакше він повертає другий операнд.

a == (4 or 5) - a дорівнює 4

a == (false or 5) - a дорівнює 5

Зверніть увагу

Логічні операції and та or можуть повертати значення будь-яких типів.

Логічні операції and і or обчислюють значення другого операнда лише тому випадку, якщо його треба повернути. Якщо це не потрібно, другий операнд не обчислюється. Наприклад:

a == (4 or f()) - виклик функції f() не відбудеться

not (логічне НЕ).

Операція not завжди повертає true чи false.

4. Операція конкатенації.

Для конкатенації (об'єднання) рядків є операція… (дві точки).

a = "Кронос".."-".."Інформ" - змінна a отримає значення "Кронос-Інформ"

Зверніть увагу

Якщо один або обидва операнди є числами, їх перетворення в рядки.

a = 0..1 – змінна a отримає значення «01»

5. Операція отримання довжини.

Lua визначена операція довжини #, яку можна використовувати для отримання довжини рядка.

a = «рядок»

len = #a - len 6

len = #«ще рядок» - len 10

Зверніть увагу

За допомогою операції # можна також дізнатися про максимальний індекс (або розмір) масиву. Докладніше - у статті «Робота з масивами в Lua».

Пріоритет операцій у Lua

У мові Lua виконання операцій здійснюється відповідно до наступного пріоритету (у порядку зменшення):

2. not # - (унарний)

6. < > <= >= ~= ==

Виклик скриптів із форм

З кожною формою (включаючи вкладені форми) пов'язаний окремий скрипт, який зазвичай містить функції, що виконують обробку подій форми та її елементів.

Коли форма запускається, її скрипт завантажується у глобальне оточення. У разі події форми чи її елемента система викликає зіставлену цієї події функцію-обробник.

Скрипт форми, хоч і не містить виклику функції module, фактично є модулем. Це означає, що змінні, оголошені у скрипті форми без ключового слова local, не виносяться у глобальне оточення і доступні лише усередині цього скрипта. Якщо необхідно зробити будь-яке значення доступним для скриптів інших форм, його слід явно визначити у глобальній таблиці _G:

local a = _G.var

Блоки операторів (інструкцій)

До основних операторів Lua відносяться:

привласнення;

умовний оператор;

оператори в організацію циклів.

Група операторів може бути поєднана в блок (складовий оператор) за допомогою конструкції do… end.

do - початок блоку

<оператор1>- тіло блоку

<оператор2>

<операторN>

end - кінець блоку

Блок відкриває нову область видимості, де можна визначати локальні змінні.

a = 5 - глобальна змінна a

local a = 20 - всередині do-end визначається локальна змінна

MsgBox(a) --> 20

MsgBox(a) --> 5 (тут звернення вже до глобальної a)

Оператор присвоєння в Lua

Надання змінює значення змінної або поля таблиці. У найпростішому вигляді привласнення може мати такий вигляд:

a = 1 - змінною a надано значення 1

a = b + c - змінною a присвоєно суму значень змінних b і с

a = f(x) - змінною a надано значення, повернене функцією f(x)

У Lua допускається так зване множинне привласнення, коли кілька змінних, що знаходяться ліворуч від оператора присвоювання, набувають значення кількох виразів, записаних праворуч від оператора присвоювання:

a, b = 1, 5 * c - a дорівнює 1; b дорівнює 5*c

Якщо змінних більше ніж значень, «зайвим» змінним надається nil.

a, b, c = 1, 2 - a дорівнює 1; b дорівнює 2; з одно nil

Якщо значень більше, ніж змінних, «зайві» значення ігноруються.

a, b = 1, 2, 3 - a дорівнює 1; b дорівнює 2; значення 3 не використане

Множинне надання можна використовувати для обміну значеннями між змінними:

a = 10; b = 20 - a дорівнює 10, b дорівнює 20

a, b = b, a - тепер a дорівнює 20, b дорівнює 10

Умовний оператор (if) у Lua

Оператор if перевіряє істинність заданої умови. Якщо умова є істинною, виконується частина коду, яка йде за ключовим словом then (секція then). В іншому випадку, виконується код, який слідує за ключовим словом else (секція else).

if a > b then

return a – якщо a більше b, повернути a

return b - інакше - повернути b

Секція else є необов'язковою.

if a< 0 then

a = 0 - якщо a менше 0, присвоїти a значення 0

Замість вкладених операторів if можна використовувати конструкцію elseif. Наприклад, наведений код:

буде простіше для сприйняття, якщо замінити його наступним:

return «Іван» - якщо a одно 1

elseif a == 2 then

return «Петро» - якщо a дорівнює 2

elseif a == 3 then

return «Сергій» - якщо a дорівнює 3

return «Немає такого гравця» - якщо a - жодне з перерахованих

Цикл з передумовою (while) у Lua

Оператор while призначений для організації циклів з передумовою та має такий вигляд:

while do

… - тіло циклу

Перед кожною ітерацією циклу перевіряється умова :

якщо умова помилкова, цикл завершується та управління передається першому оператору, що йде за оператором while;

якщо умова є істинною, виконується тіло циклу, після чого всі дії повторюються.

while i > 0 do - цикл від 10 до 1

t[i] = «поле».

a = (3, 5, 8, -6, 5)

while i > 0 do - шукаємо у масиві негативне значення

if a[i]< 0 then break end - если найдено, прерываем цикл

i = i - 1 - інакше переходимо до наступного елементу

if i > 0 then

MsgBox («Індекс негативного значення: »..i)

MsgBox ("Масив не містить негативних значень")

Примітка

Цикл з постумовою (repeat) у Lua

Оператор repeat призначений для організації циклів з постумовою і має такий вигляд:

… - тіло циклу

until

Тіло циклу виконується доти, доки умова не стане справжнім. Перевірка умови здійснюється після виконання тіла циклу, тому в будь-якому випадку тіло циклу виконається хоча б один раз.

Підсумовуємо значення масиву a, доки сума не перевищить 10

a = (3, 2, 5, 7, 9)

sum = sum + a[i]

until sum > 10

MsgBox («Складено»..i.." елементів. Сума дорівнює "..sum)

Для виходу з циклу до завершення можна використовувати оператор break.

Примітка

Докладніше про особливості використання оператора break - у статті «Оператори break та return»

Цикли з оператором for Lua

Оператор for призначений для організації циклів та допускає дві форми запису:

просту (числовий for);

розширену (універсальний for).

Проста форма оператора for

Проста форма оператора for має такий вигляд:

for var = exp1, exp2, exp3 do

… - тіло циклу

Тіло циклу виконується для кожного значення змінної циклу (лічильника) var в інтервалі від exp1 до exp2, з кроком exp3.

Примітка

Крок може не задаватися. І тут він приймається рівним 1.

for i = 1, 10 do - цикл від 1 до 10 з кроком 1

MsgBox ("i одно"..i)

for i = 10, 1, -1 do - цикл від 10 до 1 з кроком -1

MsgBox ("i одно"..i)

Зверніть увагу

Вирази exp1, exp2 і exp3 обчислюються лише один раз, перед початком циклу. Так, у прикладі нижче, функція f(x) буде викликана для обчислення верхньої межі циклу лише один раз:

for i = 1, f(x) do - цикл від 1 до значення, поверненого функцією f()

MsgBox ("i одно"..i)

Змінна циклу є локальною для оператора циклу і після закінчення не визначена.

for i = 1, 10 do - цикл від 1 до значення, поверненого функцією f()

MsgBox ("i одно"..i)

MsgBox («Після виходу з циклу i одно»..i) - Невірно! i одно nil

Зверніть увагу

Значення змінної циклу не можна змінювати всередині циклу: наслідки такої зміни непередбачувані.

Для виходу з циклу до завершення використовується оператор break.

a = (3, 5, 8, -6, 5)

for i = 1,#a do - шукаємо в масиві негативне значення

if a[i]< 0 then - если найдено...

index = i - зберігаємо індекс знайденого значення.

break - і перериваємо цикл

MsgBox ("Індекс негативного значення:"..index)

Примітка

Докладніше про особливості використання оператора break - у статті «Оператори break та return»)

Я сентиментальний програміст. Іноді я закохаюся у мови програмування, і тоді можу говорити про них годинами. Одним із цих годин я поділюся з вами.

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:

My first lua app: hello.lua print "hello world"; print("goodbye world")

Що вже можна сказати про мову:

* однорядкові коментарі починаються з двох дефісів "--"
* дужки і точки-з-комами можна не писати

Оператори мови

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

Умовні оператори (гілки else може бути) if a == 0 then print("a is zero") else print("a is not zero") end -- скорочена форма if/elseif/end (замість switch/case) if a == 0 then print("zero") elseif a == 1 then print("one") elseif a == 2 then print("two") else print("other") end -- цикл з лічильником for i = 1, 10 do print(i) end - цикл з передумовою b = 5 while b > 0 do b = b - 1 end - цикл з передумовою repeat b = b + 1 until b >= 5

ПОДУМАЙТЕ: що означатиме цикл "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

Битових операцій у мові тривалий час був, але у версії 5.2 з'явилася бібліотека bit32, що їх реалізує (як функції, як оператори).

Типи даних

Я вам збрехав, коли сказав, що у мови один тип даних. Їх у нього багато (як і у кожної серйозної мови):

* nil (рівним рахунком нічого)
* булеві числа (true/false)
* Числа (numbers) - без розподілу на цілі/речові. Просто числа.
* рядки - до речі, вони дуже схожі на рядки в паскалі
* функції - так, змінна може бути типу "функція"
* Потік (thread)
* довільні дані (userdata)
* таблиця (table)

Якщо з першими типами все зрозуміло, то що таке userdata? Згадаймо про те, що Lua — вбудована мова, і зазвичай тісно працює з компонентами програм, написаними іншими мовами. Так ось, ці «чужі» компоненти можуть створювати дані під свої потреби та зберігати ці дані разом із lua-об'єктами. Так ось, userdata - і є підводна частина айсберга, яка з точки зору мови lua не потрібна, але просто не звертати уваги на неї ми не можемо.

А тепер найважливіше у мові – таблиці.

Таблиці

Я вам знову збрехав, коли сказав, що мова має 8 типів даних. Можете вважати, що він один: все - це таблиці (це, до речі, теж неправда). Таблиця — це дуже витончена структура даних, вона поєднує властивості масиву, хеш-таблиці («ключ»-«значення»), структури, об'єкта.

Отже, ось приклад таблиці як масиву: a = (1, 2, 3) - масив з трьох елементів print(a) - виведе "2", тому що індеси зважають на одиницю - А таблиця у вигляді розрідженого масиву (У якого є не всі елементи) a = () - порожня таблиця a = 1 a = 5

ПОДУМАЙТЕ: чому дорівнює a у разі розрідженого масиву?

У прикладі вище таблиця поводиться як масив, але насправді — адже у нас є ключі (індекси) і значення (елементи масиву). І при цьому ключами можуть бути будь-які типи, не тільки числа:

A = () a["hello"] = true a["world"] = false a = 1 - або так: a = (hello = 123, world = 456) print(a["hello")) print( a.hello) -- те саме, що й a["hello"], хоча виглядає як структура з полями

До речі, раз у таблиці є ключі та значення, то можна в циклі перебрати всі ключі та відповідні їм значення:

T = (a = 3, b = 4) для key, value in pairs(t) do print(key, value) -- виведе "a 3", потім "b 4" end

А як же об'єкти? Про них ми дізнаємося трохи пізніше, спочатку про функції.

Функції

Ось приклад звичайної функції.

Function add(a, b) return a + b end print(add(5, 3)) -- надрукує "8"

Функції мови дозволяють приймати кілька аргументів та повертати кілька аргументів. Так аргументи, значення яких явно не вказані, вважаються рівними nil.

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

Function swap(a, b) return b, a end x, y = swap(x, y) -- до речі, це можна зробити без функції: x, y = y, x -- і якщо функція повертає кілька аргументів, -- а вони вам не потрібні - ігноруйте їх за допомогою -- спеціальної змінної-підкреслення "_" a, _, _, d = some_function()

Функції можуть приймати змінну кількість аргументів:

У прототипі змінне число аргументів записується як трикрапка function sum(...) s = 0 for _, n in pairs(arg) do -- до функцій звертаються до них, як до таблиці "arg" s = s + n end return a end sum(1, 2, 3) -- поверне 6 sum(1, 2, 3, 4) -- поверне 10

Оскільки функції це повноцінний тип даних, то можна створювати змінні-функції, а можна передавати функції як аргументи інших функцій

A = function(x) return x * 2 end - функція, що множить на 2 b = function(x) return x + 1 end - функція, що збільшує на 1 function apply(table, f) result = () for k, v in pairs(table) do result[k] = f(v) -- замінюємо елемент якусь функцію від цього елемента end end -- ПОДУМАЙТЕ: що повернуть виклики t = (1, 3, 5) apply(t, a) apply(t, b)

Об'єкти = функції + таблиці

Якщо ми можемо зберігати функції змінних, то й у полях таблиць теж зможемо. А це вже виходять як би методи. Для тих, хто не знайомий з ООП скажу, що основна його користь (принаймні в Lua) в тому, що функції та дані, з якими вони працюють, знаходяться в межах одного об'єкта. Для тих, хто знайомий із ОВП скажу, що класів тут немає, а успадкування прототипне.

Перейдемо до прикладів. Є у нас об'єкт, скажімо, лампочка. Вона вміє горіти і не горіти. Ну а дії з нею можна зробити дві - включити і вимкнути:

Lamp = (on = false) function turn_on(l) l.on = true end function turn_off(l) l.on = false end - це просто функції для роботи зі структурою turn_on(lamp) turn_off(lamp)

А якщо лампочку зробити об'єктом, і функції turn_off та turn_on зробити полями об'єкта, то вийде:

Lamp = (on = false turn_on = function(l) l.on = true end turn_off = function(l) l.on = false end ) lamp.turn_on(lamp) lamp.turn_off(lamp)

Ми змушені передавати сам об'єкт лампочки як перший аргумент, тому що інакше наша функція не дізнається з якою лампочкою треба працювати, щоб змінити стан on/off. Але щоб не бути багатослівними, Lua є скорочений запис, який зазвичай і використовують - lamp:turn_on(). Отже, ми вже знаємо кілька таких спрощень синтаксису:

Lamp:turn_on() -- найзагальніший запис lamp.turn_on(lamp) -- то з погляду синтаксису це теж правильно lamp["turn_on"](lamp) -- і це

Продовжуючи говорити про скорочення, функції можна описувати як явно, як поля структури, а й у зручнішій формі:

Lamp = ( on = false ) -- через точку, тоді аргумент треба вказувати function lamp.turn_on(l) l.on = true end -- через двоєточки, тоді аргумент неявно задається сам, як змінна "self" - "self" - і є лампочка, для якої викликали метод function lamp:turn_off() self.on = false end

Цікаво?

Спеціальні функції

Деякі імена функцій таблиць (методів) зарезервовані, і вони мають особливий сенс:

* __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) - обчислюють результат порівняння (<, <=, ==)
* __len(a) - викликається, коли робиться "#a"
* __concat(a, b) - викликається при "a..b"
* __call(a, …) - викликається при "a()". Змінні аргументи - це аргументи під час виклику
* __index(a, i) — звернення до a[i], за умови, що такого елемента не існує
* __newindex(a, i, v) - створення "a[i] = v"
* __gc(a) — коли об'єкт видаляється під час складання сміття

Підмінюючи ці методи, можна перевантажувати оператори та використовувати синтаксис мови для своїх цілей. Головне не перестаратися.

успадкування

Для тих, хто не знає ООП, успадкування дозволяє розширити функціональність існуючого класу. Наприклад, просто лампочка вміє вмикатися-вимикатися, а супер-ламкочка буде ще й яскравість міняти. Навіщо нам переписувати методи turn_on/turn_off, якщо їх можна повторно використовувати?

У Lua цього є поняття мета-таблиці, тобто. таблиці-предка. Кожна таблиця має одну таблицю-предок, і дочірня таблиця вміє робити все, що вміє предок.

Припустимо, що об'єкт-таблицю lamp ми вже створили. Тоді супер-лампочка виглядатиме так:

Superlamp = ( brightness = 100 ) -- вказуємо батьківську таблицю setmetatable(superlamp, lamp) -- і її методи тепер доступні superlamp:turn_on() superlamp:turn_off()

Розширення функціональності

Батьківські таблиці є у багатьох типів (ну у рядків і таблиць точно, у чисел та булевих чисел, і у nil їх немає). Допустимо, ми хочемо складати всі рядки за допомогою оператора "+", а не "..". Для цього треба замінити функцію «+» (__add) для батьківської таблиці всіх рядків:

S = getmetatable("") -- отримали батьківську таблицю рядка s.__add = function(s1, s2) return s1..s2 end -- підмінили метод -- перевіряємо a = "hello" b = "world" print(a + b) - напише "helloworld"

Власне, ми ще можемо замінити функцію print за допомогою print = myfunction, та й багато інших хакерських справ можна зробити.

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

Змінні бувають глобальні та локальні. При створенні всі змінні Lua є глобальними.

ПОДУМАЙТЕ: чому?

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

Local x local var1, var2 = 5, 3

Не забувайте про це слово.

Обробка помилок

Часто якщо виникають помилки, треба припинити виконання певної функції. Можна, звичайно, зробити безліч перевірок та викликати «return», якщо щось пішло не так. Але це збільшить обсяг коду. У Lua використовується щось на кшталт винятків (exceptions).

Помилки з'являються за допомогою функції error(x). Як аргумент можна передати все, що завгодно (те, що стосується помилки — рядковий опис, числовий код, об'єкт, з яким сталася помилка і т.д.)

Зазвичай, після цієї функції вся програма аварійно завершується. А це треба далеко не завжди. Якщо ви викликаєте функцію, яка може створити помилку (або її дочірні функції можуть створити помилку), то викликайте її безпечно за допомогою pcall():

Function f(x, y) ... якщо ... error ("failed to do somthing") end ... end status, err = pcall(f, x, y) -- f:функція, xy: її аргументи if not status then - обробити помилку err. У нашому випадку err містить текст помилки end

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

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

Між Lua та не-Lua

А якщо нам недостатньо функціональності стандартних бібліотек? Якщо у нас є наша програма на C, а ми хочемо викликати її функції Lua? І тому є дуже простий механізм.

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

#include #include #include /* власне, що робити при виклику `rand(from, to)` */ static int librand_rand(lua_State *L) ( int from, to; int x; from = lua_tonumber(L, 1); /* перший параметр функції * / to = lua_tonumber(L, 2);/* другий параметр функції */ x = rand() % (to - from + 1) + from; lua_pushnumber(L, x); * повертаємо тільки один аргумент */ ) /* в Lua "rand" відповідає нашій функції librand_rand() */ static const luaL_reg R = (("rand", librand_rand), (NULL, NULL) /* кінець списку експортованих функцій */ ); /* викликається при завантаженні бібліотеки */ LUALIB_API int luaopen_librand(lua_State *L) ( luaL_openlib(L, "librand", R, 0); srand(time(NULL)); return 1; /* завершуємося успішно */ )

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

Random = require("librand") -- завантажуємо бібліотеку print(random.rand(1, 100)) print(random.rand(0, 1))

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

#include "lua.h" #include "lauxlib.h" int main() ( lua_State *L = lua_open(); // створюємо віртуальну машину Lua luaL_openlibs(L); // завантажуємо стандартну бібліотеку luaL_dofile(L, "rand. lua"); // виконуємо скрипт lua_close(L); // закриваємо Lua return 0; )

Усе.

Ви можете писати на Lua. Якщо ви дізнаєтеся цікаві моменти про Lua, які можна було б відобразити в статті - пишіть!

У цій серії уроків, яку я задумав, обговорюватиметься мова програмування Lua. Я постараюся зробити виклад якомога доступнішим для початківців, і саме на них орієнтуватимуся. Тобто, досвідчені Lua-кодери, швидше за все, не почерпнуть звідси нічого нового (впевнений, тут вони знайдуть лише простір для причіпок та зауважень, які, власне, з їхнього боку навіть вітається), але якщо у вас за плечима немає багатого досвіду програмування , то, думаю, дещо ви винесете.

Вся серія не підпорядковуватиметься якійсь системі. Уроки будуть послідовно вводити ряд конструкцій мови, щоб до третього чи четвертого уроку ви вже могли писати свої програми. Моя мета – підштовхнути вас до самостійного вивчення мови, допомогти відчути її, а не роз'яснити від А до Я – якщо хочете освоїти мову повністю, читайте довідкове керівництво (яке, хоч і погано, перекладено російською мовою: http://www.lua . ru/doc/). Чим раніше ви перейдете від уроків "для чайників" у Мережі до вивчення довідника, тим краще.

Якщо щось незрозуміло – обов'язково поставте питання у коментарях, і я та інші учасники постараємося вам допомогти.

Lua - популярна, нескладна для освоєння інтерпретована динамічно типізована мова програмування загального призначення. Ні, вам необов'язково розуміти і половини слів, сказаних у попередній пропозиції – головне знайте, що він популярний та нескладний. До речі, простотою, а також маленьким розміром дистрибутива (близько 150 кілобайт), він і заслужив на свою популярність. Скрипти на Lua підтримуються великою кількістю програм, у тому числі іграми. World of Warcraft та S.T.A.L.K.E.R. використовують мову Lua. Мій улюблений ігровий двигун дозволить вам за допомогою Lua з легкістю створювати різноманітні ігри. Як бачите, Lua відкриває вам чималі обрії!

Перш ніж ми почнемо, вам слід облаштувати середовище для програмування: тобто знайти програму, яка б приймала написаний вами код на Lua і виконувала його: інтерпретатор. Тут є три варіанти:

1. Завантажити офіційний дистрибутив Lua з одного із сайтів, що постачають їх.

З офіційного сайту Lua можна завантажити лише вихідні коди інтерпретатора. Однак, вивчивши http://lua.org/download.html у розділі Binaries, ви можете виявити посилання на сайти з виконуваними файлами для Windows. Один з них: . Завантажте звідти один з архівів (збігається з вашою платформою: Win32 або Win64) і розпакуйте його кудись, бажано в каталог з коротким шляхом: на кшталт C:\lua. Відтепер я думаю, що ви користуєтеся Windows, і ваш інтерпретатор лежить саме там.

Користувачам операційних систем на базі Linux у цьому сенсі простіше: їм достатньо скористатися пакетним менеджером та встановити Lua з репозиторіїв. У Debian і Ubuntu це робиться командою apt-get install lua, а Fedora, Red Hat і похідних дистрибутивах - yum install lua. Проте, не довіряйте мені сліпо і зверніться до довідника вашої операційної системи, щоб дізнатися, як саме це робиться у вас.

2. Використовувати онлайн інтерпретатор.

Знаходиться за адресою http://www.lua.org/demo.html. Спочатку його може вистачити, проте надалі, коли ми торкнемося модулів, ви будете змушені використовувати офлайн-версію. Користуватися онлайн-інтерпретатором дуже просто: введіть у віконце з текстом вашу програму та натисніть кнопку Run. Програма буде виконана, у вікні Output з'явиться висновок вашої програми, а також звіти про помилки, якщо такі були допущені вами.

3. Використовувати IDE.

Наприклад, ZeroBrane Studio: http://studio.zerobrane.com/ . Є й інші – пошукайте в Інтернеті.

У ході зараз дві версії Lua: 5.1 і 5.2. Я орієнтуватимуся на останню версію - версію 5.2, але обов'язково вкажу на важливі відмінності між нею і 5.1, так як остання теж досить поширена. До речі, Lua 5.1 виконує код у півтора рази швидше за Lua 5.2, щоб ви знали.

=== Урок №1 ===

Тож почнемо. Створіть в ізольованій від сторонніх файлів папці файл main.lua та напишіть у нього:

200?"200px":""+(this.scrollHeight+5)+"px");">
-- main.lua --
print("Hello world!")

Після чого запустіть у командному рядку (не забудьте переміститися в директорію з main.lua за допомогою cd):

200?"200px":""+(this.scrollHeight+5)+"px");">
> C:\lua\lua.exe main.lua

У відповідь інтерпретатор Lua видасть:

200?"200px":""+(this.scrollHeight+5)+"px");">
Hello world!

В принципі, цього слід очікувати. У програмі ми викликали функцію print. Функція print приймає довільне число параметрів і виводить їх на екран. У цьому прикладі ми передали їй рядок (ланцюжок символів) "Hello world!". З таким же успіхом можна передати як параметр:

200?"200px":""+(this.scrollHeight+5)+"px");">
print(8) -- якесь десяткове число
-- виведе: 8

Print(0xDEADBEEF) - шістнадцяткове число
-- виведе: 3735928559

Print("0xDEADBEEF") -- а це рядок, не число! Бачите лапки?
-- виведе: 0xDEADBEEF

Print(1.35e-4) -- число з плаваючою комою (дрібне число)
- Виведе 0.000135. 1.35e-4 слід розуміти як "1.35, помножене
- на десять в мінус четвертого ступеня, якщо хто не знає.

Print((198*99)-3*500 + 14/88) - вираз
-- Виведе значення виразу: 18102.159090909. Непогана альтернатива
- Настільному калькулятору!

Print(198/7, "fertilizer", 2^9) - кілька параметрів довільного
- Типу. Буде виведено значення кожного з них, розділені знаками
- Табуляції:
-- 28.285714285714 fertilizer 512
- Зверніть увагу, що лапки навколо fertilizer не виводяться!

Print(1,35) - два числа, а не десятковий дріб 1,35!
-- Кома використовується для розділення параметрів.
- Виведе:
-- 1 35

Знак "--" - не просто імітація тире знаку, яка вставлена ​​для краси. Знаком "--" у Lua відзначаються коментарі: підказки для програміста, які ігноруються інтерпретатором, та призначені для того, щоб у коді було легше розібратися. Можете спробувати написати у програмі:

200?"200px":""+(this.scrollHeight+5)+"px");">
- print("nothing")

Інтерпретатор подумає, що це коментар, і не виконуватиме інструкцію.

Господині на замітку: якщо ви хочете надрукувати лише один рядок, можна написати виклик print так, без дужок:

200?"200px":""+(this.scrollHeight+5)+"px");">
print "Just one string"

Зручність, безперечно, сумнівна: просто майте на увазі, що так можна. Водночас такі виклики неприпустимі:

200?"200px":""+(this.scrollHeight+5)+"px");">
print 2 - не спрацює, 2 - не рядок.
print 2*2 + 6 -- тим більше не спрацює

Str = "string!!" -- надали змінній str значення "string!!"
-- про змінні читайте нижче
print str - теж не спрацює.

У кожному з вищезазначених випадків програма просто відмовиться працювати. Таким чином, у "безскобковому" виклику за назвою функції може стояти лише рядковий літерал (тобто послідовність символів, укладена в лапки), і більше нічого. У майбутньому я розповім про цю особливість трохи докладніше, але зараз вистачить і цього.

У будь-якій хорошій мові програмування можна оголошувати змінні: невеликі контейнери, які можуть містити будь-які дані. У Lua це робиться таким чином:

200?"200px":""+(this.scrollHeight+5)+"px");">
<имя_переменной> = <выражение>

Наприклад:

200?"200px":""+(this.scrollHeight+5)+"px");">
star = 8 -- Тепер у змінній star зберігається число 8
wars = "owl" - У змінній wars - рядок "owl"
jedi = 42/2 - У змінній jedi - число 21
luke = star * jedi -- У змінній luke - число 168 (так, 21 помножити на 8)

Значення змінних та виразів із ними також можна вивести на екран:

200?"200px":""+(this.scrollHeight+5)+"px");">
print(star, wars, jedi, jedi-star+luke)
- Виведе:
-- 8 owl 21 181

Тільки не намагайтеся скласти змінні star і wars - спробувавши додати 8 до "owl", ви нічого хорошого не досягнете!

Як ви мали помітити, ім'я у змінної може бути практично будь-яким: головне, щоб воно не починалося з цифри. Серйозно, ви навіть можете оголосити змінну з назвою print, і тоді функція print перестане працювати, тому що ім'я print посилатиметься на оголошену змінну. Але є група слів, які заборонено використовувати як назви змінних - це ключові слова мови, з якими ми поки що не познайомилися, але на які варто подивитися:

200?"200px":""+(this.scrollHeight+5)+"px");">
and break do else elseif end
false for function goto if in
local nil not or repeat return
then true until while

Створивши змінну з однією з цих назв, ви викличете помилку в програмі, і вона точно не працюватиме. Зверніть увагу: в Lua 5.1 ключового слова goto немає, і змінну так можна назвати, але ви краще так не робіть.
Також врахуйте, що імена змінних чутливі до регістру. Це означає, що foo, fOo, fOO і FOO - чотири різні змінні, тому якщо ви написали ім'я якоїсь змінної малими літерами, а пізніше написали його великими, то, швидше за все, програма не буде працювати коректно.

А тепер один важливий момент: що буде якщо ви випадково чи навмисно звернетеся до неіснуючої змінної? У більшості інших мов це викликає помилку, але в Lua така ситуація припустима. Вона трактується так, ніби неіснуюча змінна насправді існує, але її значення одно nil. nil- запам'ятайте це слово! - особливий тип значення Lua, який означає "ніщо". Чи не нуль і не порожній рядок (рядок виду "" - спробуйте його вивести на екран), а просто ніщо. Порівняйте це з такою моделлю: є дві людини, одна з них має банківський рахунок, але на ньому немає грошей, а в іншого банківського рахунку немає взагалі. У термінах Lua буде вважатися, що на рахунку у першого – 0 доларів, а на рахунку у другого – nil. І навіть не доларів, а просто nil. Сподіваюся, я вас не заплутав.

Спробуйте, наприклад, запустити таку програму:

200?"200px":""+(this.scrollHeight+5)+"px");">
-- main.lua --
foo = "bar"
print(foo, baz)
- Виведе:
-- bar nil

Таким чином, у змінної baz якої немає, але вважається, ніби вона є, значення nil, і функція print розуміє це і виводить його на екран у вигляді рядка "nil". У Lua є хороший метод перевірки існування змінної: якщо значення змінної не дорівнює nil, вона принаймні оголошена. З іншого боку, можна явно оголосити змінну, рівну nil:

200?"200px":""+(this.scrollHeight+5)+"px");">
cool_var=nil

Так можна робити, і хоча це на перший погляд і здається дурним, так іноді роблять. У наступних уроках ви дізнаєтеся, хто і навіщо, і, напевно, почнете робити так само. Іноді, звісно ж.
Будьте обережні з nil"ом: надрукувати nil можна, але робити з ним арифметичні операції не можна! Тобто, якщо print(nil) зійде вам з рук, то конструкція на кшталт 99+nil викличе помилку, навіть якщо вам хотілося б, щоб 99+ nil дорівнювало 99. Повірте, я теж засмутився, коли дізнався.

Резюме:
1. Ми дізналися про функцію print, що вона вміє і як правильно викликати її без дужок.
2. Дізналися, як оголошувати змінні, як обчислювати висловлювання (щоправда, дуже трішки), які можуть бути імена у змінних.
3. Дізналися про nil, перейнялися його містичною загадковістю і здобули впевненість у тому, що в майбутньому багато буде пов'язано з ним.

Для допитливих і бажаючих зміцнити свої знання пропоную прості вправи,які можна не виконувати, якщо ви почуваєтеся і так достатньо компетентним:
1. Напишіть програму, яка виводить приспів вашої улюбленої пісні.
2. Спробуйте вивести наступні вирази. Спробуйте зрозуміти, чому деякі з них працюють, а деякі – ні. Подивіться, які помилки викликають вислови, що не спрацювали.

200?"200px":""+(this.scrollHeight+5)+"px");">
2+"string";
6 + "14";
"box" - "vox";
1 * "11b"
"148" * "1e6";


3. Напишіть програму, яка обмінює дві змінні значення. Тобто:

200?"200px":""+(this.scrollHeight+5)+"px");">
a = 6502
b = 8086


Зробіть так, щоб a дорівнювала 8086, а b - 6502. Для цього створіть третю змінну і здійсніть нехитрі перестановки. Переконайтеся, що завдання вирішено правильно, викликавши print(a,b) до обміну та print(a,b) після.

Сподобалась стаття? Поділіться їй