﻿<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="../style.xsl"?>

<doc path="../" style="styles.css" toc="">
<name>Язык программирования Lua. Учебник для начинающих</name>
<body>
<div style="padding-left:10px; width:800px">
<h1>Введение</h1>
<img class="float-right" alt="Lua Logo" src="./images/lua-small.png"/>
<p>Основным мотивом для написания этого текста стало отстутствие на просторах интернета
какого-либо внятного учебника по Lua, для чайников и не только, причем на русском языке.
Документация на русском есть, а с чего начать - непонятно. 
Есть хорошая книжка - "Programming in Lua" (причем нужно именно 2-е издание), но ее почему-то даже в
электронном виде нигде нет. Мне удалось найти только препринт 1-го издания, и разумеется на английском.
После двухгодичной разработки скриптов для хабов на Lua стало ясно, что уж "для чайников" я и сам руководство сделаю.
Через некоторое время после осознания этого факта появился черновик, который долгое время оставался совсем убогим
и кратким, и вот только сейчас он становится похож на учебник. Отмечу также, что на просторах интернета много
различных статей вида "как на Lua сделать что-то эдакое", но полного подробного учебника пока что не наблюдается.
Либо встречаются руководства для продвинутых, которые уже что-то знают и хотят "расшИрить и углУбить" (с) свои знания.
Итак, приступим-с...
</p>

<r>Disclaimer: это учебное описание языка Lua, а не полное руководство. Некоторые аспекты излагаются
с некоторой вольностью, чтобы не затмевать суть дела. Да простят меня за это великие умы мира сего.
</r>

<p>Вопросы, комментарии, замечания и предложения по данному опусу просьба постить <a href="http://forum.vip-zone.su/index.php?showtopic=20">на форум в эту тему</a>,
<a href="images/feedback.png">по e-mail, нарисованному тут</a> или в jabber <b>dmvn@jabber.ru</b>.
Замечания горячо приветствуются!
</p>

<h2>Обзор Lua</h2>

<p>Lua -- относительно несложный и в то же время мощный язык, часто применяемый как средство расширения
функциональности в многих приложениях, играх, и, что нам в данном случае более интересно,
в DC-хабах. В частности, он поддерживается в Verlihub (специальным плагином) и в PtokaX.
Как и многие другие скриптовые языки, он позволяет выполнять код без предварительной компиляции
(т.е. является интерпретируемым). С одной стороны, это часто ускоряет и упрощает разработку
(изменил пару строчек, перезапустил, и всё), с другой стороны, некторые разновидности ошибок отлавливаются
только <i>в процессе выполнения</i> данного куска кода.
Скажем, вы вызываете функцию, которой не существует, или передаёте ей неверное количество параметров: если
эта строчка в силу логики работы программы не выполнится, вы про свою ошибку даже не узнаете :)
А вот если выполнится, интерпретатор неприлично выругается.
Такого почти не бывает в компилируемых языках, в которых код тщательно проверяется на стадии синтаксической
проверки, компиляции или линковки.
</p>

<p>В отличие например от Pascal, Lua не является строго типизированным языком. При инициализации переменных
им не нужно указывать тип -- он сам разберется, а объявление переменных фактически не требуется, так как
объявлением является присвоение значения. Преобразование из одного
типа в другой часто происходит неявно, что упрощает читаемость программы.
При этом для любой переменной можно в процессе выполнения узнать ее тип с помощют специального оператора.
Более того, тип одной и той же переменной может быть изменен в процессе ее существования при присвоении
нового значения (другого типа). Это явление называется <i>динамической типизацией</i>.
В Lua (как, например, в javascript), имеется специальное значение <b>nil</b> (аналог <b>null</b>),
означающее отсутствие 'содержательных' данных. Как и C/C++, Lua является <b>регистро-чувствительным</b>.
Переменная AAA и aaa --- это разные переменные!
</p>

<h2>Примеры программ в данном тексте и интертрепация</h2>

<p>Все приводимые ниже примеры вы можете проверить тут: <a href="http://www.lua.org/cgi-bin/demo">Lua demo</a>
-- вставляете код в форму и жмёте кнопочку <b>Run</b>. Ниже образуется вторая форма с выводом вашей программы.
Это возможно благодаря тому, что Lua -- интерпретатор и не требует предварительной компиляции кода.
Однако для него есть и компилятор <b>luac</b>, который переваривает программу в некий байт-код, который
уже быстрее разбирается интерпретатором, что ускоряет загрузку и выполнение программы. Однако скорость
выполнения самого скрипта в компилированном и в обычном виде примерно одинакова, в чем я предлагаю убедиться
читателю самостоятельно.
</p>

<p>В заголовке слово "интерпретация" не случайно было написано с опечаткой. Дело в том, что формально
отделить компилируемые языки от интерпетируемых - занятие соврешенно бесперспективное, и степень
"интерпретируемости" - это скорее какая-то вещественная (дробная) характеристика от 0 до 1.
Ведь даже программа на ассемблере (или, давайте уж по полной - "машинный" код) тоже в известном смысле
<b>интерпретируется</b> процессором! Так что по сути разница лишь в том, кто интерпретирует код -- железяка
или программа (скажем виртуальная машина той же Java). С другой стороны, если зашить интерпретатор Lua в процессор (а почему нет, собственно?),
компилятором он от этого не станет :)
</p>

<h2>Стандартная библиотека</h2>

<p>За образец изложения информации о любом языке программирования я беру книгу Бьерна Страуструпа
"The C++ Programming Language", в которой, если я не ошибаюсь, ни разу не упоминается
ни одна конкретная операционная система или какая-нибудь библиотека ввода-вывода, которая имеет
право иметь различную реализацию (или отсутствовать вовсе!) в различных реализациях языка и в разных ОС.
Поэтому я стараюсь минимизировать использование функций, которые могут существенно зависеть от ОС -
ведь никто не знает, на каких системах возьмется писать программу кто-нибудь из читателей.
Досадное исключение - функция <b>print</b>, которая осуществляет вывод на консоль
(а точнее - на стандартный поток вывода stdout), который, к счастью, в том или ином виде присутствует в большинстве ОС.
</p>

<p>Следует также отметить и такую особенность Lua. Он часто используется как встроенный язык для
написания различных расширений, плагинов и тд. В этих случаях у нас вообще, как правило, нет возможности
отлаживать нашу программу с помощью print-ов, так как ее вывод зачастую может подавляться.
Например, при отладке скриптов для DC-хабов удобно использовать отладочную печать
в виде сообщений пользователям хаба (чат хаба используется как консоль вывода). Но это только один из примеров;
если читатель сразу возьмется за применение Lua в качестве embedded-языка, пусть подберет себе способ
для вывода отладочных сообщений вместо print.
</p>

<p>По тем же соображениям мы вообще не будем рассматривать такие например операции, как ввод данных с клавиатуры,
так как их реализация не имеет ничего общего в различных операционных системах.
Файловый же ввод-вывод чуть более стандартизован (и самое главное, бывает нужен в приложениях), поэтому
его мы всё-таки коснемся в соответствующей главе. То же самое относится к аргументам командной строки программы.
</p>

<h2>Элементы и особенности языка</h2>

<p>Как и в большинстве языков, в Lua есть переменные, операции (арифметические, строковые, и тд),
операторы (циклы, ветвление), функции (то есть именованные подпрограммы с параметрами), и библиотека
стандартных функций, обеспечивающих взаимодействие программы с ОС и некоторые другие стандартные действия.
Оператор цикла <b>for</b> чаще всего используется как конструкция <b>for each</b> и очень применяется для выполнения
операций над массивами (таблицами и мета-таблицами), хотя он допускает и классический арифметический вариант с
переменной-счётчиком. Циклы <b>while</b> и <b>repeat-until</b> полностью аналогичны большинству языков.
Оператор ветвления <b>if</b> допускает секцию <b>elseif</b>, тем самым фактически делает
ненужным оператор выбора (case, switch, case of). Как и в C/C++, в Lua нету различий между процедурами и функциями,
и те и другие декларируются ключевым словом <b>function</b>, а возвращаемое значение и его тип определяется
внутри кода самой функции инструкцией <b>return</b>. И я не сильно ошибусь, если скажу что на этом список
ключевых слов языка практически исчерпывается - их действительно очень немного (разумеется, если не учитывать
функции стандартной библиотеки, коих имеется превеликое множество.
</p>

<p>В предыдущем абзаце по сути дела не было упомянуто почти ни одного хитроумного слова, не знакомого человеку,
который знает уже какой-нибудь язык программирования. За исключением, пожалуй, одного - загадочного слова
<i>мета-таблица</i>. Как мы потом узнаем, в них скрывается вся соль Lua. Пока можно сказать, что это прежде всего,
обычные таблицы, но кроме хранения данных они позволяют ещё и перегружать стандартные операции для таблиц,
как это делается в С++ с помощью конструкции <b>operator()</b>. Если написанное Вам пока не понятно - не обращайте внимания.
На некоторое время мы забудем про всю эту жуть и сначала разберем основы языка, которые, во-первых, элементарны,
а во-вторых, очень похожи на базовые конструкции в других языках. Я не случайно ссылаюсь частенько на С/C++,
так как многие читатели вполне могут его знать, и им будет проще. Что же касается мета-таблиц, то им будет посвящена
целая отдельная глава.
</p>


<h2>Структура кода</h2>

<p>В отличие от С++, Pascal и других строгих языков, в Lua исполнение кода программы начинается последовательно,
если этот код не является телом функции.
Отдельные конструкции языка разделяются пробелом с необязательной точкой с запятой в конце. Я по привычке их ставлю :)
</p>

<ex title="Пример 0" src="./src/ex000.lua"><span class="line-num">1</span>&#160;<comm>-- это наша первая программа на Lua
</comm><br /><span class="line-num">2</span>&#160;<print/>(<str>"Hello from World!"</str>);
<br /><span class="line-num">3</span>&#160;
<br /><span class="line-num">4</span>&#160;<comm>-- а это функция, которая не вызовется
</comm><br /><span class="line-num">5</span>&#160;<function/> MyFunction()
<br /><span class="line-num">6</span>&#160;<tab/><print/>(<str>"Hello from Function!"</str>);
<br /><span class="line-num">7</span>&#160;<end/><br /></ex>
<p>При запуске будет выведена только первая строка (Hello from World), так как функцию MyFunction никто не вызовет, 
и то что написано внутри, не выполнится.
</p>

<h2>Простейшие примеры</h2>

<p>
Сейчас мы разберем несколько простеньких программ, на которых я постараюсь доказать вам, что Lua -- это очень просто.
</p>

<ex title="Пример 1: классический Hello world" src="./src/ex001-hello.lua"><span class="line-num">1</span>&#160;<print/>(<str>"Hello World!"</str>);
<br /><span class="line-num">2</span>&#160;<br /></ex>
<p>Я думаю, не надо пояснять, что она выведет;) В Lua не требуются всякого рода "точки входа"
программы, как в C или Pascal. Исполнение скриптов начинается с первой строки,
за исключением тел функций. Они выполняются тогда и только тогда, когда к ним происходит обращение.
Следующий пример чуть более содержателен:</p>

<ex title="Пример 2: переменные" src="./src/ex002-vars.lua"><span class="line-num">1</span>&#160;a = 1;
<br /><span class="line-num">2</span>&#160;<print/>(<str>"Ура, я научился использовать переменные: a = "</str>..a);<br /></ex>
<p>Что же выведет наша программа в примере 2? Между переменной <b>a</b> и строкой используется операция
склейки (по-научному - <i>конкатенации</i>) строк -- две точки подряд. Она выведет текст и значение переменной,
то есть число 1. Не правда ли, всё просто?
</p>

<p>Тут же следует сказать о том, что в Lua можно не использовать
разделитель <b>;</b> (точку с запятой) для разделения инструкций. Лично мне ее ставить привычнее,
к тому же в С++ их всё равно приходится ставить - так зачем переучиваться? 
Поэтому я буду их использовать в своих примерах. Кроме того, это вносит дополнительную наглядность.
</p>

<p>Строковые константы в Lua можно писать как в двойных, так и в одинарных кавычках, как вам удобнее.
Если в тексте встречаются кавычки -- можете написать в апострофах, даже не придётся их экранировать символом <b>\</b>,
как это приходится делать в C++. Например вот так:</p>

<ex title="Пример 3: строки" src="./src/ex003-strings.lua"><span class="line-num">1</span>&#160;strApos = <str>"Строка с 'апострофами' внутри"</str>;
<br /><span class="line-num">2</span>&#160;strQuot = <str>'Строка с "кавычками" внтури'</str>;<br /></ex>
<p>А как же быть, если нам надо по каким-то причинам написать строку, в которой (о ужас) есть и кавычки, и апострофы?
В этом случае поможет только экранирование:</p>

<ex title="Пример 4: строковый винегрет" src="./src/ex004-strings-mix.lua"><span class="line-num">1</span>&#160;str = <str>"Строка с <squot/>кавычками<squot/> и 'апострофами' внутри"</str>;<br /></ex>
<p>Если вам нужно осуществить перевод строки, или вставить какой-либо другой служебный символ, пишем так же, как это делается в С/C++. 
</p>

<ex title="Пример 5: переносы и табуляция в строках" src="./src/ex005-tabs.lua"><span class="line-num">1</span>&#160;<print/>(<str>"А это строка <snew/> с переносами <snew/> строк.<snew/> а вот тут табуляция <stab/> и ещё <snew/> один перенос."</str>);<br /></ex>
<p>Будет выведено следующее:</p>
<code open="Вывод примера 5" src="./src/ex005-output.txt"><span class="line-num">1</span>&#160;А это строка
<span class="line-num">2</span>&#160; с переносами
<span class="line-num">3</span>&#160; строк.
<span class="line-num">4</span>&#160; а вот тут табуляция    и ещё
<span class="line-num">5</span>&#160; один перенос.</code>
<p>
На этом мы заканчиваем обзор и переходим к систематическому изложению. Наша программа на ближайшее будущее будет такой:
вначале мы обсудим операции и типы данных, потом операторы языка, потом более детально познакомимся с объявлением переменных.
</p>

<h1>Глава 1. Базовые конструкции языка </h1>

<h2>Типы данных: Основы</h2>

<h3>Простые типы</h3>

<p>Сейчас мы кратко обсудим основные типы данных в Lua, не углубляясь в детали. Это нам потребуется для того,
чтобы можно было сочинять более содержательные примеры. Позже мы вернемся к типам данных и переменным и 
особенностям их объявления.</p>

<p>Основными (и наиболее часто используемыми) типами данных в Lua являются числа, строки, логические значения,
а также <i>массивы</i> и <i>таблицы</i> из этих значений. Явным образом тип данных никак не указывается -
интерпретатор определяет его сам, поэтому многие простые конструкции можно писать чисто интуитивно,
и это будет правильно.
</p>

<ex title="Типы данных - введение" src="./src/ex005-types-intro.lua"><span class="line-num">1</span>&#160;i=1; <comm>-- число
</comm><br /><span class="line-num">2</span>&#160;d=3.1415; <comm>-- тоже число
</comm><br /><span class="line-num">3</span>&#160;sum=i+d; <comm>-- сумма двух чисел
</comm><br /><span class="line-num">4</span>&#160;str=<str>"string"</str>; <comm>-- строка</comm><br /></ex>
<p>Больше ничего пока про простые типы я говорить не буду (сознательно) и предлагаю читателью больше пользоваться
собственной интуицией при чтении примеров программ. В сложных языках (том же С/С++) это не всегда работает,
а вот в Lua - очень даже. Вообще, приятно изучать язык, в котором есть должная степень наглядности кода -
он делает именно то, что написано и ничего более, без особых ухищрений со стороны программиста.</p>

<h3>Массивы и таблицы</h3>
<a name="tables"/>

<p>Что такое массив, наверное всем понятно. Это набор данных одного и того же типа, занумерованный
последовательностью целых чисел (индексами) с "шагом" 1. Обычно индексация делается либо от 0 до N-1,
где N - количество элементов массива, либо от 1 до N. И тот и другой подход имеет свои плюсы и минусы;
в более низкоуровневых языках вроде С/C++ применяется (и оказывается реально удобнее!) индексация с нуля,
а вот в Lua "прижилась" индексация массивов с 1. Как мы потом узнаем, это всё не очень принципиально,
и при правильном построении программ об этом вообще не приходится думать.</p>

<p>Как объявляются массивы и как с ними работать? Очень просто:</p>

<ex title="Типы данных - массивы" src="./src/ex005-types-arrays.lua"><span class="line-num">1</span>&#160;<comm>-- способ 1
</comm><br /><span class="line-num">2</span>&#160;array1=<brackets/>; <comm>-- новый пустой массив
</comm><br /><span class="line-num">3</span>&#160;array1[1] = <str>'first element'</str>;
<br /><span class="line-num">4</span>&#160;array1[2] = <str>'second element'</str>;
<br /><span class="line-num">5</span>&#160;
<br /><span class="line-num">6</span>&#160;<comm>-- способ 2
</comm><br /><span class="line-num">7</span>&#160;array2={[1]=<str>'first'</str>, [2]=<str>'second'</str>};
<br /><span class="line-num">8</span>&#160;
<br /><span class="line-num">9</span>&#160;<print/>(array1[1], array2[2]);<br /></ex>
<p>Как видите, всё очень наглядно. Размер массива можно узнать следующим образом:</p>

<ex><print/>(#array1);</ex>

<p>Более подробно о массивах, их размерах и других тонкостях мы поговорим в отдельной главе,
а пока познакомимся с таблицами. Если читатель знаком, например, с С++ и библиотекой STL,
то для него таблица "в первом приближении" - это стандартный контейнер <b>std::map</b>.
Для "остальных смертных" придётся сказать, что таблица - это <i>ассоциативный массив</i>,
представляющий собой множество пар { (key, value) }, для которого определена операция []
(получение элемента value по ключу key). Немного забегая вперед, скажем что массивы в Lua
- это на самом деле тоже таблицы с числовыми значениями ключа key от 1 до размера массива.
</p>

<p>Вышесказанное показалось вам слишком сложным и непонятным? Ничего страшного, это просто
формальное определение интуитивно простых понятий. Сейчас мы рассмотрим пример и всё станет понятно.
Например, у нас есть телефонная записная книжка, в которой контактам сопоставлено (для простоты)
по одному телефонному номеру. В Lua эту книжку можно было бы задать так:
</p>

<ex title="Типы данных - таблицы" src="./src/ex005-types-tables.lua"><span class="line-num">1</span>&#160;Phones = {
<br /><span class="line-num">2</span>&#160;<tab/>[<str>'Вася Пупкин'</str>] = <str>'(495) 504–50–21'</str>,
<br /><span class="line-num">3</span>&#160;<tab/>[<str>'Изольда Кшыштопопвжецкая'</str>] = <str>'2-12-85-06'</str>,
<br /><span class="line-num">4</span>&#160;<tab/>[<str>'МЧС'</str>] = <str>'112'</str>,
<br /><span class="line-num">5</span>&#160;}<br /></ex>
<p>В качестве индексов в таблицах можно использовать не только строки и числа, а вообще
всё что угодно, в том числе другие таблицы. Обращаться к элементам можно по этим самым индексам.
Само собой, при попытке взять элемент,
которого не существует, вам вернется значение <b>nil</b>.</p>

<a name="tables-example"/>
<p>Для таблиц со строковыми ключами, которые записаны латинскими буквами и не содержат
в себе пробелов (то есть по сути являются идентификаторами языка), можно использовать упрощенный
синтаксис при обращении к элементам таблицы, делая ее похожей на структуру (или класс).
А именно:</p>

<ex title="Таблицы: OOP-style" src="./src/ex005-tables-simp.lua"><span class="line-num">1</span>&#160;t = <brackets/>;
<br /><span class="line-num">2</span>&#160;t.field_x = 10;
<br /><span class="line-num">3</span>&#160;t.field_y = 20;
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;<print/>(t[<str>'field_x'</str>], t[<str>'field_y'</str>]);<br /></ex>
<p>Здорово, не правда ли? Запись через точку в присвоении выглядит горзадо понятнее,
чем в распечатке значений со скобками. Самое главное, у нас появляется возможность двоякой работы с таблицами
- как со структурами и как с массивами (ну, разве что с соблюдением более строгих правил для имен полей).
</p>

<p>На этом мы временно оставим таблицы в стороне - этого нам будет достаточно для понимания
некоторых дальнейших примеров.</p>

<h2>Операции в Lua</h2>

<p>Настало время поговорить о самых простых средствах языка - операциях.
Как и во всех остальных языках, в Lua имеется более чем джентльменский набор операций -
арифметических, логических и строковых.
Начнем разумеется с простого -- с арифметики.</p>

<h3>Арифметические операции</h3>

<p>Сколько их, арифметических операций? четыре? Неправильно, шесть:
сложение, вычитание, умножение, деление, взятие остатка от деления и возведение в степень.
Обозначения их стандартны и используются во многих других языках:</p>
<ex>
+ - * / % ^
</ex>
<p>Приоритеты операций, разумеется, аналогичны обычной арифметике. Но есть и отличия.
Например, операция деления целых чисел не является целочисленной (как это происходит в С).
Так что выражение
</p>
<ex>
25/2^2
</ex>
<p>будет равно 6.25, а не 6, как в языке С/C++. Lua по сути не делает различий
между вещественными и целыми числами. Приятно отметить, что он позволяет работать
с достаточно большими целыми числами (в текущих реализациях - до 2^46), не переходя
к экспоненциальной форме хранения.</p>

<p>Кроме арифметических операций, имеется ещё некоторое количество функций математической
библиотеки, добавляющие нам разного рода округления, стандартные математические функции типа синусов и косинусов,
но их мы обсудим позже.</p>

<h3>Логические операции</h3>

<p>Основные операции "И", "ИЛИ", "НЕ" в Lua записываются как <b>and</b>, <b>or</b>, <b>not</b>
и полностью аналогичны другим языкам. Пример:
</p>

<ex title="Пример 6: Железная логика-1" src="./src/ex006-logic1.lua"><span class="line-num">1</span>&#160;<if/> <true/> <and/> <false/> <then/>
<br /><span class="line-num">2</span>&#160;<tab/><print/>(<str>"Вот это ерунда!"</str>);
<br /><span class="line-num">3</span>&#160;<end/><br /></ex>
<p>Операции сравнения похожи на операции в С/C++. Сравнение здесь пишется двумя знаками равенства <b>==</b>,
а "не равно" -- комбинацией <b>~=</b> (тильда и знак равенства).
</p>

<ex title="Пример 7: Железная логика-2" src="./src/ex007-logic2.lua"><span class="line-num">1</span>&#160;<if/> 1 <neq/> 2 <then/>
<br /><span class="line-num">2</span>&#160;<tab/><print/>(<str>"Не врет железяка"</str>);
<br /><span class="line-num">3</span>&#160;<end/><br /></ex>
<p>Есть ещё один элегантный случай применения булевых операций, кроме обычных логических выражений.
Выглядит он так:
</p>

<ex title="Пример 7.5: Использование or" src="./src/ex007-or-sample.lua"><span class="line-num">1</span>&#160;number = <nil/>;
<br /><span class="line-num">2</span>&#160;number = number <or/> 0;
<br /><span class="line-num">3</span>&#160;<print/>(number);
<br /><span class="line-num">4</span>&#160;number = 10;
<br /><span class="line-num">5</span>&#160;number = number <or/> 0;
<br /><span class="line-num">6</span>&#160;<print/>(number);<br /></ex>
<p>Первый раз будет напечатано <b>0</b>, а второй раз -- <b>10</b>. Таким образом, если один из операндов <b>or</b> равен
<b>nil</b>, выражение "x <b>or</b> y" будет равно противоположному операнду.
Это удобно для инициализации переменных заведомо корректными значениями (отличными от nil), если заранее значение
не известно. Конструкция выглядит гораздо красивее, чем аналогичное сооружение с <b>if</b>.
</p>

<h3>Строковые операции</h3>

<p>Со строками можно делать много всего, но операция для работы с ними всего
одна - <i>конкатенация</i> (или, по-кухонному, склейка) двух строк. Надо отметить,
что для её обозначения пока что не выработалось общемирового стандарта, поэтому
в Lua она обозначается двумя точками (к слову, в PHP для этой цели используется точка, в JavaScript - знак плюс).
Пример тривиален, но мы его всё-таки напишем:</p>
<ex title="Склейка строк">
str=<str>"Hello"</str>..<str>"World"</str>;
</ex>

<p>Lua допускает склейку строк с числами - в этом случае последние преобразуются в десятичную запись.
Пример: </p>

<ex title="Пример 8: Склейка строки и числа" src="./src/ex008-concat-num.lua"><span class="line-num">1</span>&#160;str=<str>"Current Lua version is "</str>..5.14;<br /></ex>
<p>Но ни в коем случае не пытайтесь склеивать строку с неинициализированной переменной
(или, что то же самое, со значением <b>nil</b>):</p>

<ex title="АнтиПример 9: ошибочная склейка с nil" src="./src/ex009-concat-nil.lua"><span class="line-num">1</span>&#160;nothing=<nil/>;
<br /><span class="line-num">2</span>&#160;str=<str>"nihil test "</str>..nothing;<br /></ex>
<p>Если переменная nothing не инициализировалась ранее, программа "вылетит" с ошибкой примерно такого содержания:
"attempt to concatenate global 'nothing' (a nil value)". Разумеется, вылетит только во время выполнения, так
как заранее никто не знает, будет где-нибудь задано этой переменной значение или нет.</p>

<h3>Смешение типов</h3>

<p>Любопытный читатель наверняка захочет применить какие-нибудь операции к переменным тех типов,
к которым "официально" их применять нельзя. И тут его ждет некоторое разочарование - они будут восприняты
языком вполне адекватно и естественно. Например:
</p>

<ex title="Пример 9.5: Смешение типов" src="./src/ex009-mix-types.lua"><span class="line-num">1</span>&#160;num1 = <str>'5'</str> + <str>'7'</str>; <comm>-- результат - число
</comm><br /><span class="line-num">2</span>&#160;<print/>(num1); <comm>-- 12
</comm><br /><span class="line-num">3</span>&#160;num2 = <str>'11'</str> * <str>'13'</str> * <str>'7'</str>; <comm>-- результат тоже число
</comm><br /><span class="line-num">4</span>&#160;<print/>(num2); <comm>-- 1001
</comm><br /><span class="line-num">5</span>&#160;str = <str>'1234'</str>..<str>'5678'</str>;
<br /><span class="line-num">6</span>&#160;<print/>(str); <comm>-- 12345678
</comm><br /><span class="line-num">7</span>&#160;str = <str>'1234'</str>..<str>'4444'</str>/2;
<br /><span class="line-num">8</span>&#160;<print/>(str); <comm>-- 12342222</comm><br /></ex>
<p>В комментариях написаны результаты операций и их типы. Особенно забавна последняя операция, в которой "строковая"
константа (по приоритету) делится на число, а потом склеивается с другим числом. Синтаксис это позволяет, но... вообще лучше всегда использовать
явное приведение типов, о котором мы расскажем чуть позже.
</p>

<h2>Операторы языка</h2>

<p>Сейчас мы перейдем к обсуждению того, без чего не напишешь ни одной серьезной программы.
А именно, об операторах языка для управления логикой работы программы.
Как и в любом уважающем себя языке, в Lua есть ветвление (if..then..else) и циклы (for, while, repeat).
Их мы сейчас и обсудим.
</p>

<p>Отметим, что в Lua нету так называемых "операторных скобок", вроде <b>{ ... }</b>  в С/С++ и <b>begin .. end</b> в Pascal.
Поэтому большинство операторов имеют форму <b>ключевое слово ... end</b> (кстати, забегая вперед, скажем что то же самое относится к объявлению функций). Сейчас мы подробно обсудим каждый из операторов, а начнем с самого часто используемого -- условного оператора <b>if</b>.
</p>

<h3>if..elseif..elseif..else..end</h3>

<p>Синтаксис его таков (поскольку в Lua переносы строк не имеют значения, будем для красоты использовать многострочную запись):</p>

<p>Первый, самый простой вариант без <b>else</b>:</p>

<ex title="if: простой вариант" src="./src/ex010-if1.lua"><span class="line-num">1</span>&#160;<if/> логическое_выражение <then/>
<br /><span class="line-num">2</span>&#160;<tab/><comm>-- ...
</comm><br /><span class="line-num">3</span>&#160;<tab/><comm>-- тут идут инструкции, выполняющиеся если выражение истинно
</comm><br /><span class="line-num">4</span>&#160;<tab/><comm>-- ...
</comm><br /><span class="line-num">5</span>&#160;<end/><br /></ex>
<p>Вместо многоточий пишите то, что должно быть выполнено, если <b>логическое_выражение</b>
может быть (неявно) приведено к логическому <b>true</b>. В Lua значения <b>nil</b> и <b>false</b>
воспринимаются как ложь, всё остальное - как истина (<span>даже значение 0</span>). Это немного
непривычно для программистов на С и приучает писать сравнения более аккуратно.</p>

<p>Второй вариант, с <b>else</b>:</p>

<ex title="if: обычный вариант" src="./src/ex011-if2.lua"><span class="line-num">1</span>&#160;<if/> логическое_выражение <then/>
<br /><span class="line-num">2</span>&#160;<tab/><comm>-- тут идут инструкции, выполняющиеся если выражение истинно
</comm><br /><span class="line-num">3</span>&#160;<else/>
<br /><span class="line-num">4</span>&#160;<tab/><comm>-- а тут -- если оно ложно
</comm><br /><span class="line-num">5</span>&#160;<end/><br /></ex>
<p>Если условие верно, выполняется первый блок, если нет -- второй. Альтернативных условных блоков 
может быть много, в этом случае добавляется <b>elseif</b>:</p>

<ex title="if: длинный вариант" src="./src/ex012-if3.lua"><span class="line-num">1</span>&#160;<if/> выражение1 <then/>
<br /><span class="line-num">2</span>&#160;<tab/><comm>-- сюда идем, если выражение1 истинно
</comm><br /><span class="line-num">3</span>&#160;<elseif/> выражение2 <then/>
<br /><span class="line-num">4</span>&#160;<tab/><comm>-- сюда идем, если выражение2 истинно
</comm><br /><span class="line-num">5</span>&#160;<elseif/> выражение3 <then/>
<br /><span class="line-num">6</span>&#160;<tab/><comm>-- сюда идем, если выражение3 истинно
</comm><br /><span class="line-num">7</span>&#160;...
<br /><span class="line-num">8</span>&#160;<else/> 
<br /><span class="line-num">9</span>&#160;<tab/><comm>-- сюда идем, если не выполнилось ни одно из предыдущих условий
</comm><br /><span class="line-num">10</span>&#160;<end/><br /></ex>
<r>TODO: пример на if</r>

<h3>Цикл for</h3>

<p>Цикл имеет два варианта синтаксиса: арифметический и for-each. Разберем сначала первый,
для этого хватит пары примеров:</p>

<ex title="for: арифметический" src="./src/ex013-for1.lua"><span class="line-num">1</span>&#160;<for/> i = 1,10,1 <do/>
<br /><span class="line-num">2</span>&#160;<tab/><print/>(<str>"Переменная i внутри цикла равна "</str>..i);
<br /><span class="line-num">3</span>&#160;<end/><br /></ex>
<p>Тут переменная пробегает значения от 1 до 10 и программа выводит 10 строчек с её значениями. Третье
число означает шаг увеличения переменной (если оно равно 1, его можно не писать вообще).
Важная особенность: выражения, определяющие начальное, конечное значение и шаг переменной цикла вычисляются
<b>один</b> раз при входе в него. Если потребуется выйти "досрочно" - используйте оператор <b>break</b>,
о котором будет рассказано далее.
</p>

<p>Арифметическая форма цикла <b>for</b> используется редко ввиду особенностей языка, а точнее ввиду его области наболее частого применения.
Гораздо чаще в Lua применяется второй вариант (если он сейчас будет совсем не понятен, ничего страшного -
дальше мы ещё будем очень подробно говорить о таблицах, ключах и индексах).
Он обычно называется for-each, так как некоторое действие (в данном случае тело цикла) делается для каждого
элемента из некоторого множества (в примере - для каждой записи таблицы).</p>

<ex title="for: модификация for-each" src="./src/ex014-for2.lua"><span class="line-num">1</span>&#160;<comm>-- зададим таблицу из 3 элементов:
</comm><br /><span class="line-num">2</span>&#160;AdminNicks = {
<br /><span class="line-num">3</span>&#160;<str>"root"</str>,
<br /><span class="line-num">4</span>&#160;<str>"admin"</str>,
<br /><span class="line-num">5</span>&#160;<str>"master"</str>
<br /><span class="line-num">6</span>&#160;}
<br /><span class="line-num">7</span>&#160;<comm>-- пробежимся по таблице в цикле:
</comm><br /><span class="line-num">8</span>&#160;<for/> k,val <in/> <pairs/>(AdminNicks) <do/>
<br /><span class="line-num">9</span>&#160;<tab/><print/>(<str>"К таблице в данном случае можно обращаться так: "</str>..val..<str>", а можно так: "</str>..AdminNicks[k]..<str>"."</str>);
<br /><span class="line-num">10</span>&#160;<end/>
<br /><span class="line-num">11</span>&#160;<br /></ex>
<p>Программа выведет три строки с упоминанием в них элементов таблицы. Переменная <b>k</b> пробегает индексы
таблицы (т.е. массива), а <b>val</b> -- значения элементов по этим индексам.
Здесь мы попутно бегло познакомились с очень полезной конструкцией <b>pairs</b>, которая выдаёт ключ (индекс)
таблицы и ее элемент. К этому примеру мы ещё вернемся позже.
</p>

<p>В качестве более интересного примера для циклов напишем программу, которая выведет
все простые числа от 2 до 1000 (делящиеся только на 1 и само себя). Алгоритм самый
примитивный, который только может быть (перебор всех делителей).</p>

<ex title="for: поиск простых чисел" src="./src/ex015-for3-primes.lua"><span class="line-num">1</span>&#160;<function/> isPrime(x) <comm>-- функция проверки простоты
</comm><br /><span class="line-num">2</span>&#160;<tab/><for/> d = 2, x-1, 1 <do/>
<br /><span class="line-num">3</span>&#160;<tab/><tab/><if/> (x % d) <eq/> 0 <then/> <return/> <false/>; <end/>
<br /><span class="line-num">4</span>&#160;<tab/><end/>
<br /><span class="line-num">5</span>&#160;<tab/><return/> <true/>
<br /><span class="line-num">6</span>&#160;<end/>
<br /><span class="line-num">7</span>&#160;
<br /><span class="line-num">8</span>&#160;<for/> i = 2, 1000, 1 <do/>
<br /><span class="line-num">9</span>&#160;<tab/><if/> isPrime(i) <then/> <print/>(i); <end/>
<br /><span class="line-num">10</span>&#160;<end/>
<br /><span class="line-num">11</span>&#160;<br /></ex>
<p>Здесь скобки вокруг <b>x % d</b> стоят исключительно для наглядности.
Приоритет операции <b>%</b> (остаток от деления, так же как и в С) выше, чем приоритет сравнения.</p>

<h3>Цикл while</h3>

<p>Удобство цикла for проявляется тогда, когда мы знаем, сколько раз нам этот цикл крутить.
А если нам нужно какое-то действие выполнять, пока верно некоторое условие, удобнее использовать цикл <b>while</b>.
Синтаксис его очень простой:
</p>

<ex title="Синтаксис while" src="./src/ex016-while-syntax.lua"><span class="line-num">1</span>&#160;<while/> логическое_выражение <do/>
<br /><span class="line-num">2</span>&#160;<tab/><comm>--операции, выполняемые пока выражение истинно
</comm><br /><span class="line-num">3</span>&#160;<end/><br /></ex>
<p>При входе в цикл значение выражения проверяется на истинность. Если оно ложно, цикл не выполняется ни разу.
Если истинно, выполняется первая итерация, и снова проверяется условие. Если оно снова истинно -
выполняется вторая итерация, и так далее. Если наше выражение так и останется истинным - цикл будет бесконечным.
Наш более содержательный пример - нахождение положительного корня уравнения <b>x^2=2</b>
методом половинного деления на отрезке от 1 до 2. Его значение мы и так знаем: sqrt(2), но мы вычислим
его двумя способами и сравним результаты.
</p>

<ex title="Пример использования while" src="./src/ex017-while.lua"><span class="line-num">1</span>&#160;<function/> f(x)
<br /><span class="line-num">2</span>&#160;<tab/><return/> x^2 - 2;
<br /><span class="line-num">3</span>&#160;<end/>
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;left=1.0; <comm>-- левая граничная точка
</comm><br /><span class="line-num">6</span>&#160;right=2.0; <comm>-- правая граничная точка
</comm><br /><span class="line-num">7</span>&#160;m = left; <comm>-- начальное приближение корня 
</comm><br /><span class="line-num">8</span>&#160;
<br /><span class="line-num">9</span>&#160;<while/> <math/>.<abs/>(f(m)) &gt; 0.000000001 <do/>
<br /><span class="line-num">10</span>&#160;<tab/><if/> f(m) &gt; 0 <then/>
<br /><span class="line-num">11</span>&#160;<tab/><tab/>right=m;
<br /><span class="line-num">12</span>&#160;<tab/><else/>
<br /><span class="line-num">13</span>&#160;<tab/><tab/>left=m;
<br /><span class="line-num">14</span>&#160;<tab/><end/>
<br /><span class="line-num">15</span>&#160;<tab/>m = (left+right)/2;
<br /><span class="line-num">16</span>&#160;<end/>
<br /><span class="line-num">17</span>&#160;<print/>(<str>"Root value: "</str>, m);
<br /><span class="line-num">18</span>&#160;<print/>(<str>"Sqrt(2)   : "</str>, <math/>.<sqrt/>(2));
<br /><span class="line-num">19</span>&#160;<print/>(<str>"Difference: "</str>, <math/>.<abs/>(m-<math/>.<sqrt/>(2)));
<br /><span class="line-num">20</span>&#160;<br /></ex>
<p>Тут, как Вы наверное уже заметили, есть сюрприз в виде неизвестных нам пока функций
<b>math.abs</b> и <b>math.sqrt</b>. Знакомые с другими языками разумеется догадались,
что это модуль (абсолютное значение) числа и квадратный корень соответственно.
Я намеренно включаю в свои примеры некоторые функции из стандартной библиотеки, чтобы
читатель постепенно их тоже осваивал по ходу пьесы.
</p>

<p>Если выполнить программу, мы увидим, что результаты отличаются только в 11-м знаке.
Неплохая точность, не правда ли?</p>

<h3>Цикл repeat..until</h3>

<p>Цикл <b>repeat..until</b> отличается от цикла с пред-условием (while) тем, что всегда выполняется хотя бы один раз.
Синтаксис его аналогичен while c точностью до зеркального отражения:</p>

<ex title="Синтаксис repeat" src="./src/ex018-repeat.lua"><span class="line-num">1</span>&#160;<repeat/>
<br /><span class="line-num">2</span>&#160;<comm>-- тело цикла
</comm><br /><span class="line-num">3</span>&#160;<until/> логическое выражение<br /></ex>
<p>Цикл выполняется до тех пор, пока выражение не станет истинным. Следующий пример печатает первое число,
которое больше 2000 и делится на 13:</p>

<ex title="Пример использования repeat" src="./src/ex019-repeat.lua"><span class="line-num">1</span>&#160;x=2000;
<br /><span class="line-num">2</span>&#160;<repeat/>
<br /><span class="line-num">3</span>&#160;<tab/>x=x+1;
<br /><span class="line-num">4</span>&#160;<until/> (x % 13) <eq/> 0;
<br /><span class="line-num">5</span>&#160;<print/>(x);<br /></ex>
<h3>Блок do..end</h3>

<p>Эта конструкция сама по себе ничего не делает, это просто блок команд, аналогичный {...} в С/C++.
Как мы потом узнаем, она влияет на видимость переменных, их глобальность и время жизни.
С его помощью удобно выделять логически разные куски кода, если по каким-то причинам их неудобно
выносить в отдельные функции. Переменные, обявленные локальными внутри блока, погибают при выходе
из его, поэтому целесообразно применять его например в тех случаях, когда мы имеем дело с "большими"
(по объему памяти) переменными, и т.д.
</p>

<h2>Управляющие конструкции в циклах</h2>

<p>Прервать выполнение цикла досрочно можно с помощью оператора <b>break</b>. Его можно использовать только внутри циклов.
Синтаксис его использования таков:</p>

<ex title="Пример использования break" src="./src/ex019-break.lua"><span class="line-num">1</span>&#160;i=0;
<br /><span class="line-num">2</span>&#160;<while/> <true/> <do/> <comm>-- организуем бесконечный цикл
</comm><br /><span class="line-num">3</span>&#160;<tab/><print/>(<str>"Бесконечный цикл"</str>);
<br /><span class="line-num">4</span>&#160;<tab/><if/> i &gt; 10000 <then/>
<br /><span class="line-num">5</span>&#160;<tab/><tab/><print/>(<str>"Всё, хватит"</str>);
<br /><span class="line-num">6</span>&#160;<tab/><tab/><break/>;
<br /><span class="line-num">7</span>&#160;<tab/><end/>
<br /><span class="line-num">8</span>&#160;<tab/>i=i+1;
<br /><span class="line-num">9</span>&#160;<end/><br /></ex>
<h2>Переменные: более пристальный взгляд</h2>

<h3>Как правильно объявлять переменные?</h3>

<p>В Lua можно определять переменные практически где угодно. Вернее, поскольку специальное объявление
как таковое не требуется, можно вводить переменную именно тогда, когда уже известно ее значение.
Это позволяет избежать ошибок с использованием неинициализированных значений.
Стиль, навязываемый скажем, языком Pascal, в котором переменные объявляются в специальной секции,
совершенно порочен и кроме ошибок ничего не даёт. Кто-то скажет, что так лучше видно, какие в процедуре
есть переменные и какие у них типы, однако же никто не знает, используются они вообще в программе
или нет, а уж чему равны - тем более не ясно. Поэтому, объявляйте переменную там и только там,
где она вам пригодилась.
</p>

<ex title="Глобальные переменные" src="./src/ex020-vars.lua"><span class="line-num">1</span>&#160;text=<str>"some string"</str>;
<br /><span class="line-num">2</span>&#160;more_text=<str>"second string"</str>..text;
<br /><span class="line-num">3</span>&#160;<print/>(more_text);<br /></ex>
<p>Тут ничего хитрого нет. Объявляется глобальная переменная text, ей задаётся некоторое значение, а потом
переменной more_text присваивается склейка строковой константы и значения первой переменной.
Вообще, любая переменная в Lua является по умолчанию глобальной.
А вот следующий пример уже кому-то может показаться необычным. Во всяком случае, в других языках
такие конструкции не работают:
</p>

<ex title="Переменные через запятую" src="./src/ex021-vars2.lua"><span class="line-num">1</span>&#160;var_first, var_second = 1, <str>"text"</str>;
<br /><span class="line-num">2</span>&#160;<print/>(var_first);
<br /><span class="line-num">3</span>&#160;<print/>(var_second);<br /></ex>
<p>Здесь будет напечатано сначала 1, а потом text. На первый взгляд не очень понятно, в чем смысл
такой конструкции - казалось бы лучше объявить сначала одну переменную, а потом другую.
Но этот прием очень часто применяется в более сложных примерах, где используются функции,
возвращающие не одно значение, а сразу много. Тогда это становится удобным.
А если вам нужно поменять две переменные <b>a</b> и <b>b</b> местами, это можно сделать очень элегантно:
</p>

<ex title="Обмен">
a,b=b,a;
</ex>

<p>Не правда ли, красиво? То же самое можно сделать с тремя, четырьмя переменными (например, переставить их по кругу).
Разумеется, в таких конструкциях мы должны внимательно следить за порядком переменных, но это уже, как говорится,
дело техники. При всём при этом Lua <b>не</b> понимает, например, вот таких вот "извращений в стиле С":
</p>

<ex title="Lua is not a C++" type="wrong">
var1=var2=var3=var4=1;
</ex>

<h3>Область видимости переменных</h3>

<p>Хороший тон программирования предполагает использовать локальные переменные всюду, где это возможно, и
и стараться не использовать глобальных переменных вообще.
Поэтому теперь мы будем везде стараться объявлять локальные переменные. Делается это с помощью ключевого
слова <b>local</b>.</p>

<ex title="Локальные переменные" src="./src/ex022-local.lua"><span class="line-num">1</span>&#160;<local/> var=<str>'some string'</str>;<br /></ex>
<p>Как это всё работает? продемонстрируем на примере:</p>

<ex title="Локальные переменные" src="./src/ex023-local2.lua"><span class="line-num">1</span>&#160;var=<str>"ext variable"</str>;
<br /><span class="line-num">2</span>&#160;<if/> 1 <neq/> 2 <then/>
<br /><span class="line-num">3</span>&#160;<tab/><local/> var=<str>"int variable"</str>;
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;<print/>(var);<br /></ex>
<p>Как Вы думаете, что напечатает наш пример? Правильно, Вы угадали - он напечатает строку <b>ext variable</b>,
потому что переменная внутри оператора if является локальной по отншению к внешней переменной,
и значение будет задано у нее, а не переопределено значение внешней переменной.
Разумеется, наш пример корректен, поскольку условие верно, и мы попадаем внутрь if-а.
</p>

<p>Разумеется, если написать вот так:</p>

<ex title="Локальные переменные" src="./src/ex024-local3.lua"><span class="line-num">1</span>&#160;<local/> var=<str>"ext variable"</str>;
<br /><span class="line-num">2</span>&#160;<if/> 1 <neq/> 2 <then/>
<br /><span class="line-num">3</span>&#160;<tab/>var=<str>"int variable"</str>;
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;<print/>(var);<br /></ex>
<p>... то переменная у нас тут всего одна и будет изменено именно ее значение, и программа выведет <b>int variable</b>.</p>

<p>В общем случае <i>область видимости переменной</i> - это блок некоторого оператора (if, for, while)
блок операторов <b>do..end</b>, тело функции или же вся программа (точнее файл). Обладая этим понятием,
можно сформулировать общее правило:
<b>среди всех переменных с данным названием, встречающихся в коде, в выражении используется ближайшая
в данной области видимости</b> (если расстоянием считать глубину вложенности областей).
</p>

<p>Пожалуй, для полноты картины стоит привести ещё один (не очень хороший, но допустимый) пример кода.
К сожалению, он потребует объявления функции, но я надеюсь, интуитивно понятен:</p>

<ex title="Хитроумная видимость и инициализация" src="./src/ex025-local-bad.lua"><span class="line-num">1</span>&#160;<function/> create_var()
<br /><span class="line-num">2</span>&#160;<tab/>global_var=<str>"value"</str>;
<br /><span class="line-num">3</span>&#160;<end/>
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;<print/>(global_var);
<br /><span class="line-num">6</span>&#160;create_var();
<br /><span class="line-num">7</span>&#160;<print/>(global_var);<br /></ex>
<p>Поначалу можно подумать, что будет выведено значение <b>nil</b> два раза, так как "глобальную"
переменную global_var никто не инициализирует, а то что делается внутри функции, так и останется в ее пределах.
Ан нет: сначала будет напечатано <b>nil</b>, а второй строкой -- слово "value", потому что внутри функции
идёт обращение именно к <b>глобальной</b> сущности. Разумеется, стоит нам написать внутри функции заветное
слово <b>local</b> в этом присвоении, как ситуация преобразится радикальным образом, и будет выведено два раза
слово <b>nil</b>.
Вообще, таких неявных конструкций следует избегать, поскольку они часто порождают ошибки.
</p>

<p>Осталось заметить, что модификатор <b>local</b> применим так же и к функциям в Lua и влияет
на их область видимости (доступности). Это удобно, когда функция заведомо будет использоваться
только в рамках данного файла, в котором она описана и не приведет к "засорению" глобального пространства имён.</p>

<h2>Типы данных. Динамическая типизация</h2>

<h3>А какие вообще в Lua бывают типы?</h3>
<p>Наверное многие уже поняли, что в Lua имеют право на жизнь как минимум числа
(целые и вещественные, между ними нету разницы), строки и таблицы. На самом деле и это тоже не всё.
Фокус в том, что функция в Lua - это тоже тип данных, и с функциями можно
обращаться почти так же, как с обычными переменными - присваивать одной функции другую функцию, и многое другое.
Но про функции у нас ещё будет отдельный длинный разговор, вернемся на землю к "обычным" переменным и типам.
Если читатель ещё не забыл введение, там упоминался ещё один специальный тип <b>nil</b>, озанчающий отсутствие
какого-либо объекта. Но и на этом список типов не завершается, поскольку в Lua бывают ещё thread-ы (потоки).
Но о них мы поговорим позже.
</p>

<p>Объявление переменной (точнее, инициализация), как уже говорилось выше, и определяет ее тип в данный момент времени.
Почему "в данный момент", а не вообще? Потому что есть динамическая типизация, о которой речь чуть ниже.
Вот несколько примеров определений переменных разных типов:
</p>

<ex title="Переменные разных типов" src="./src/ex026-types.lua"><span class="line-num">1</span>&#160;<local/> var_int=10;
<br /><span class="line-num">2</span>&#160;<local/> var_float=3.1415926;
<br /><span class="line-num">3</span>&#160;<local/> var_str=<str>"this is a string"</str>;
<br /><span class="line-num">4</span>&#160;<local/> var_table=<brackets/>;
<br /><span class="line-num">5</span>&#160;<local/> var_func = <function/>() <print/>(<str>"hello from <function/>"</str>); <end/>;
<br /><span class="line-num">6</span>&#160;<local/> var_nil = <nil/>;<br /></ex>
<p>Вот по сути и всё, что в Lua допустимо с точки зрения типов. Последняя запись примера с <nil/> на самом
деле не имеет смысла: любая неинициализированная переменная и так имеет значение <nil/>.
Другое дело что в более сложной программе такое присваивание может вполне себе иметь нетривиальный смысл.
Чуть забегая вперед, можно сказать что такая запись ведёт к разрушению данной переменной, если до этого она
ссылалась на некоторый объект.
</p>

<h3>Динамическое определение типа переменной</h3>

<p>Теперь мы поясним смысл выражения "в данный момент" из предыдущего параграфа. Сейчас мы повторим наш пример,
смело заменив в нем имена переменных на какое-нибудь одно (назовем ее просто var):</p>

<ex title="Одна переменная разных типов" src="./src/ex027-dynamic-types.lua"><span class="line-num">1</span>&#160;<local/> var=10;
<br /><span class="line-num">2</span>&#160;<print/>(var, <type/>(var)); <comm>-- сейчас это число, будет напечатано '10 number'
</comm><br /><span class="line-num">3</span>&#160;<local/> var=3.1415;
<br /><span class="line-num">4</span>&#160;<print/>(var, <type/>(var)); <comm>-- сейчас это тоже число, снова будет напечатано '3.1415  number'
</comm><br /><span class="line-num">5</span>&#160;<local/> var=<str>"text"</str>;
<br /><span class="line-num">6</span>&#160;<print/>(var, <type/>(var)); <comm>-- а сейчас это уже строка, будет напечатано 'text string'
</comm><br /><span class="line-num">7</span>&#160;<local/> var=<brackets/>;
<br /><span class="line-num">8</span>&#160;<print/>(var, <type/>(var)); <comm>-- мутируем дальше: var стало таблицей, напечатается 16-ричный адрес и слово 'table'
</comm><br /><span class="line-num">9</span>&#160;<local/> var = <function/>(a,b) <return/> a+b; <end/>;
<br /><span class="line-num">10</span>&#160;<print/>(var(1,2), <type/>(var)); <comm>-- дальше - больше: теперь var - это функция, напечатается '3 function'
</comm><br /><span class="line-num">11</span>&#160;<local/> var = <nil/>;
<br /><span class="line-num">12</span>&#160;<print/>(<type/>(var)); <comm>-- а теперь переменная погибла, напечатается 'nil nil'</comm><br /></ex>
<p>Проницательный читатель уже давно догадался, что два минуса "--" озанчают строчные комментарии в Lua, а оператор <b>type</b>
возвращает тип переменной.
</p>

<h1>Функции</h1>

<p>Маленькое лирическое отступление о функциях... Основа читаемости любого кода - это его структурированность.
Если написать текст программы "одним куском", его никто не поймет, а его длина в большинстве случаев
увеличится во много раз по сравнению с другими реализациями,
а скорость работы возрастёт незначительно. Самый простой способ структурировать программу -- разбить её на подпрограммы,
снабдив каждую из них именем. Эти подпрограммы в народе называются процедурами и функциями. Точнее говоря, в разных
языках - по-разному, но термин "функция" есть в большинстве языков.
Из популярных, пожалуй, только в ассемблере устоялся термин "процедура", поскольку там функции
синтаксически не отличаются от процедур. Обычно под "процедурой" подразумевают подпрограмму, 
которая делает некоторое действие, но не возвращает никаких значений (например, именно так дела
обстоят в Pascal/Delphi), а функция - это подпрограмма, имеющая "результат" в виде
некоторого объекта, называемого "возвращаемым значением" (return value) функции. А например в языках С и С++ эта грань,
напротив, стерта и там все подпрограммы с точки зрения синтаксиса являются функциями.
Так... к чему я это всё? А, ну да. Мне просто хотелось сказать что Lua в этом плане похож на С/С++ и там
любая подпрограмма - это функция.
А теперь обо всём по порядку.
</p>

<h2>Простые (классические) примеры функций</h2>

<p>Синтаксис объявления (описания) функции таков:</p>

<ex title="Описание функции" src="./src/ex028-func-def.lua"><span class="line-num">1</span>&#160;<function/> function_name(&lt;arg_list&gt;)
<br /><span class="line-num">2</span>&#160;<tab/><comm>-- function body
</comm><br /><span class="line-num">3</span>&#160;<end/><br /></ex>
<p>Описание функции начинается с ключевого слова <b>function</b>, далее в скобках перечисляются
аргументы функции (только их имена, никаких типов) которые являются локальными переменными внутри функции.
Перед ключевым словом <b>function</b> можно, как и в случае переменных, написать слово <b>local</b>,
что повлияет на область видимости самой функции.
Аргументами функции обычно является последовательность переменных, разделенных запятой. Почему "обычно"? Потому что есть
ещё один интересный и полезный случай, который мы разберем чуть ниже.
</p>

<p>В отличие, скажем, от С, в Lua нету понятия "протопипа" (заголовка) функции. Она видна везде
в своей области видимости, в том числе и выше своего описания.</p>

<p>Выход из функции происходит либо по достижению последней инструкци в функции, либо с помощью оператора <b>return</b>.
Если return-а нет, наша функция будет возвращать значение <b>nil</b> (то есть на самом деле ничего возвращать не будет).
</p>

<p>Вот пример содержательной функции, которая осуществляет склейку двух строк с проверкой их типов и пустых значений.</p>

<ex title="Безопасная склейка строк" src="./src/ex029-func-ex.lua"><span class="line-num">1</span>&#160;<function/> SafeConcat(a, b)
<br /><span class="line-num">2</span>&#160;<tab/><if/> <not/> a <then/> <return/> b; <end/>
<br /><span class="line-num">3</span>&#160;<tab/><if/> <not/> b <then/> <return/> a; <end/>
<br /><span class="line-num">4</span>&#160;<tab/><return/> a<concat/>b;
<br /><span class="line-num">5</span>&#160;<end/>
<br /><span class="line-num">6</span>&#160;
<br /><span class="line-num">7</span>&#160;<print/>(SafeConcat(<str>"test1"</str>, <nil/>));
<br /><span class="line-num">8</span>&#160;<print/>(SafeConcat(<nil/>, <str>"test2"</str>));
<br /><span class="line-num">9</span>&#160;<print/>(SafeConcat(<str>"test3.1"</str>, <str>"test3.2"</str>));
<br /><span class="line-num">10</span>&#160;<print/>(SafeConcat(4.1, 4.2));<br /></ex>
<p>Этой функцией можно склеивать числа, строки, nil-ы -- всё что угодно, ошибки не произойдет.
Потом мы узнаем, как такое можно делать более красиво, но это будет потом.
</p>

<h2>Функции с переменным числом аргументов</h2>

<p>Как и в С/C++, в Lua можно задавать функции с переменным числом аргументов. В этом случае они передаются
туда как массив с зарезервированным именем <b>arg</b> c индексами от 1 до n, где <b>n=arg.n</b>
(буква 'n' -- это тоже на самом деле индекс массива, имеющий строковый тип и значение <b>'n'</b>. Если это сейчас
не очень понятно - ничего страшного, всё встанет на свои места, когда мы разберемся с таблицами, и иожете пока просто
это выражение (arg.n) воспринимать как заклинание).
Вместо имен параметров функции нужно написать троеточие. Вот пример, который склеивает все свои аргументы
(разумеется, кроме nil-ов) в одну строку:</p>

<ex title="Многоточие" src="./src/ex030-func-dots.lua"><span class="line-num">1</span>&#160;<function/> ConcatMultiple(...)
<br /><span class="line-num">2</span>&#160;<tab/><local/> str=<str>""</str>;
<br /><span class="line-num">3</span>&#160;<tab/><for/> i=1,<arg/>.n <do/>
<br /><span class="line-num">4</span>&#160;<tab/><tab/><if/> <arg/>[i] <neq/> <nil/> <then/>
<br /><span class="line-num">5</span>&#160;<tab/><tab/><tab/>str=str..<arg/>[i];
<br /><span class="line-num">6</span>&#160;<tab/><tab/><end/>
<br /><span class="line-num">7</span>&#160;<tab/><end/>
<br /><span class="line-num">8</span>&#160;<tab/><return/> str;
<br /><span class="line-num">9</span>&#160;<end/>
<br /><span class="line-num">10</span>&#160;
<br /><span class="line-num">11</span>&#160;<print/>(ConcatMultiple(<str>'a'</str>,<str>'b'</str>,<nil/>,<str>'c'</str>,<str>'d'</str>));
<br /><span class="line-num">12</span>&#160;<br /></ex>
<p>Когда пойдет разговор о таблицах, мы ещё вспомним этот пример и реализуем эту же функцию иначе.
Но вернемся к нашему многоточию. В нашем примере мы заменили им все аргументы функции. Разумеется,
это не всегда удобно, поэтому есть возможность использовать и такие конструкции:</p>

<ex title="Параметры и многоточие" src="./src/ex031-func-dots-mixed.lua"><span class="line-num">1</span>&#160;<function/> PrintVarsWithPrefix(prefix, ...)
<br /><span class="line-num">2</span>&#160;<tab/><print/>(prefix..<str>":"</str>);
<br /><span class="line-num">3</span>&#160;<tab/><for/> i = 1, <arg/>.n <do/>
<br /><span class="line-num">4</span>&#160;<tab/><tab/><tab/><print/>(<str>"   "</str>..<arg/>[i]);
<br /><span class="line-num">5</span>&#160;<tab/><end/>
<br /><span class="line-num">6</span>&#160;<end/>
<br /><span class="line-num">7</span>&#160;
<br /><span class="line-num">8</span>&#160;<local/> a=1;
<br /><span class="line-num">9</span>&#160;<local/> b=<str>"string"</str>;
<br /><span class="line-num">10</span>&#160;<local/> c=1.5;
<br /><span class="line-num">11</span>&#160;
<br /><span class="line-num">12</span>&#160;PrintVarsWithPrefix(<str>"Variables"</str>, a, b, c);<br /></ex>
<p>Подобные описания функций можно применять, когда некоторые параметры имеют для нас особое значение,
а некоторые в известном смысле одинаковые и нам не очень важно, кто из них первый кто последний.
Наш последний пример выведет вот что:
</p>

<ex title="Параметры и многоточие" src="./src/ex031-func-dots-mixed-out.txt"><span class="line-num">1</span>&#160;Variables:
<br /><span class="line-num">2</span>&#160;   1
<br /><span class="line-num">3</span>&#160;   string
<br /><span class="line-num">4</span>&#160;   1.5<br /></ex>
<p>Обратите внимание, что нумерация аргументов функции в этом случае остаётся прежней: <b>arg[1]</b>
- это первый "динамический" параметр, а не параметр prefix. Поставить многоточие перед именованными аргументами
синтаксис Lua, разумеется, запрещает - в этом случае невозможно было бы определить количество динамических
и обычных параметров.
</p>

<h2>Параметры (аргументы) командной строки</h2>

<p>Раз уж мы затронули вопрос аргументов функций, уместно тут же заметить, что при старте скрипта массив
<b>arg</b> заполняется параметрами командной строки, переданными нашему скрипту. Тут наблюдается полная аналогия с C/C++ и 
необязательными аргументами функции <b>main(int argc, char**argv)</b>.
Вот примерчик, демонстрирующий их использование:
</p>

<ex title="Параметры командной строки" src="./src/ex032-main-args.lua"><span class="line-num">1</span>&#160;<if/> <not/> <arg/> <then/>
<br /><span class="line-num">2</span>&#160;<tab/><print/>(<str>"No <arg/> array defined"</str>);
<br /><span class="line-num">3</span>&#160;<tab/>os.exit(1)
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;
<br /><span class="line-num">6</span>&#160;<print/> (<str>"Here are my command line argumnets:"</str>);
<br /><span class="line-num">7</span>&#160;<if/> <arg/>[0] <then/> <print/>(<str>"Script name is: "</str>..<arg/>[0]); <end/>
<br /><span class="line-num">8</span>&#160;<if/> <arg/>[-1] <then/> <print/>(<str>"Interpreter name is "</str>..<arg/>[-1]); <end/>
<br /><span class="line-num">9</span>&#160;<if/> <arg/>[1] <then/> <print/>(<str>"First script parameter is "</str>..<arg/>[1]); <end/>
<br /><span class="line-num">10</span>&#160;<if/> <arg/>[2] <then/> <print/>(<str>"Second script parameter is "</str>..<arg/>[2]); <end/><br /></ex>
<p>Если Вы запустите этот скрипт консольным интерпретатором Lua, Вы увидите примерно следующее
(само собой, вид приглашения командной строки будет у вас другим):
</p>

<ex title="Параметры командной строки - вывод" src="./src/ex032-main-args-out.txt"><span class="line-num">1</span>&#160;[vdm@f12 luatest]$ lua ex032-main-args.lua argument1 argument2 argument3
<br /><span class="line-num">2</span>&#160;Here are my command line argumnets:
<br /><span class="line-num">3</span>&#160;Script name is: ex032-main-args.lua
<br /><span class="line-num">4</span>&#160;Interpreter name is lua
<br /><span class="line-num">5</span>&#160;First script parameter is argument1
<br /><span class="line-num">6</span>&#160;Second script parameter is argument2
<br /><span class="line-num">7</span>&#160;[vdm@f12 luatest]$<br /></ex>
<h2>Возвращаемые значения функции и оператор return</h2>

<p>В отличие от многих других языков, в Lua возвращаемых значений у функции может быть много, и при этом не надо их
оформлять в виде какой-нибудь специальной структуры. Просто пишите их через запятую, и в том же порядке присваивайте.
Например, напишем функцию, которая возвращает сразу и частное, и остаток от деления двух чисел. Она будет очень простая
и будет состоять из единственной интересующей нас строчки с <b>return</b>-ом.</p>

<ex title="Множественный return" src="./src/ex033-multi-return.lua"><span class="line-num">1</span>&#160;<function/> Div(a, b)
<br /><span class="line-num">2</span>&#160;<tab/><return/> <math/>.<floor/>(a/b), a % b;
<br /><span class="line-num">3</span>&#160;<end/>
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;<local/> X=57;
<br /><span class="line-num">6</span>&#160;<local/> Y=17;
<br /><span class="line-num">7</span>&#160;
<br /><span class="line-num">8</span>&#160;<local/> quot, res = Div(X, Y);
<br /><span class="line-num">9</span>&#160;<print/>(quot, res);
<br /><span class="line-num">10</span>&#160;<if/> quot * Y + res <eq/> X <then/>
<br /><span class="line-num">11</span>&#160;<tab/><print/>(<str>"All right"</str>);
<br /><span class="line-num">12</span>&#160;<end/><br /></ex>
<p>Я думаю, что тут происходит - и так понятно.
Для полной ясности остаётся лишь сказать, что <b>math.floor</b> возвращает целую часть числа, округленную вниз.</p>

<p>Разумеется, если нам нужен только один параметр (скажем, частное), можно написать так:</p>

<ex>
<local/> quot = Div(X,Y);
</ex>

<p>А если нужен только остаток, первый параметр нужно будет тоже куда-то присвоить. Для этого очень часто используют
переменную с именем "_":</p>

<ex>
<local/> _, res = Div(X,Y);
</ex>

<p>Выглядит может быть слегка коряво, но этот приём (и именно такое имя переменной) очень часто применяется
в реально существующих проектах на Lua, поэтому изобретать что-то оригинальное в данном случае не хочется.
Если Вам нужно добраться до третьего занчения, никто не мешает использовать "мусорную" переменную дважды:
</p>

<ex>
<local/> _,_,var = SomeFunctionReturningThreeParams();
</ex>

<p>Проницательный читатель скорее всего уже догадался, что если функция возвращает меньше параметров,
чем мы написали в присвоении, последние (недостающие) будут заполнены значением <b>nil</b>. Никаких
ошибок вам интерпретатор при этом не выдаст, а молчаливо сделает то, что Вы ему сказали.
В нижеследующем примере сначала напечатается "1  2  3", а потом "5  nil  nil":</p>

<ex title="Множественный return с багом" src="./src/ex034-multi-return-bug.lua"><span class="line-num">1</span>&#160;<function/> one(a)
<br /><span class="line-num">2</span>&#160;<tab/><return/> a;
<br /><span class="line-num">3</span>&#160;<end/>
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;<local/> x,y,z=1,2,3;
<br /><span class="line-num">6</span>&#160;<print/>(x,y,z);
<br /><span class="line-num">7</span>&#160;x,y,z=one(5);
<br /><span class="line-num">8</span>&#160;<print/>(x,y,z);<br /></ex>
<p>Разумеется, количество возвращаемых значений и их типы могут быть непостоянными. Следующий пример
может показаться слегка бредовым, но тем не менее любопытным.
В нем будет функция, которая возвращает переданный параметр "как есть", если он строковый, а если передали
число - возвращает его же, преобразованное в строковый формат с выравниванием на 10 символов, и второе значение "true"
как флаг осущественной конвертации:</p>

<ex title="Return разных типов" src="./src/ex035-return-dynamic-types.lua"><span class="line-num">1</span>&#160;<function/> Convert(var)
<br /><span class="line-num">2</span>&#160;<tab/><if/> <type/>(var) <eq/> <str>"string"</str> <then/>
<br /><span class="line-num">3</span>&#160;<tab/><tab/><return/> var;
<br /><span class="line-num">4</span>&#160;<tab/><end/>
<br /><span class="line-num">5</span>&#160;<tab/><if/> <type/>(var) <eq/> <str>"number"</str> <then/>
<br /><span class="line-num">6</span>&#160;<tab/><tab/><return/> string.format(<str>"%10d"</str>, var), <true/>;
<br /><span class="line-num">7</span>&#160;<tab/><end/>
<br /><span class="line-num">8</span>&#160;<tab/><return/> <str>"Bug <in/> your code!"</str>;
<br /><span class="line-num">9</span>&#160;<end/>
<br /><span class="line-num">10</span>&#160;
<br /><span class="line-num">11</span>&#160;<local/> r1=Convert(2);
<br /><span class="line-num">12</span>&#160;<print/>(r1);
<br /><span class="line-num">13</span>&#160;<local/> r2=Convert(200);
<br /><span class="line-num">14</span>&#160;<print/>(r2);
<br /><span class="line-num">15</span>&#160;<local/> r3=Convert(20000);
<br /><span class="line-num">16</span>&#160;<print/>(r3);
<br /><span class="line-num">17</span>&#160;<local/> r4=Convert(<str>"some string"</str>);
<br /><span class="line-num">18</span>&#160;<print/>(r4);
<br /><span class="line-num">19</span>&#160;
<br /><span class="line-num">20</span>&#160;<print/>(Convert());<br /></ex>
<p>Кстати, обратите внимание на последнюю строчку. Там вызывается наша функция Convert без параметров,
хотя по идее должна принимать один параметр. Неужели интерпретатор на это ругнется? Конечно же нет!
Функция будет вызвана, вот только параметр будет равен <b>nil</b>. В соответствии с тем, что написано в нашей
функции, последней строкой будет напечатано "Bug in your code!".</p>

<h2>Прочие особенности вызова функций</h2>

<p>В Lua допустимы конструкции следующего вида: пусть у вас есть функция, которая принимает (например) два параметра,
и вторая функция, которая возвращает два параметра. Можно использовать такую запись:</p>

<ex title="Передача двух параметров сразу" src="./src/ex036-return-to-func.lua"><span class="line-num">1</span>&#160;<function/> exchange(a, b)
<br /><span class="line-num">2</span>&#160;<tab/><return/> b, a;
<br /><span class="line-num">3</span>&#160;<end/>
<br /><span class="line-num">4</span>&#160;
<br /><span class="line-num">5</span>&#160;<function/> greater(a, b)
<br /><span class="line-num">6</span>&#160;<tab/><if/> <math/>.<abs/>(a) &gt; <math/>.<abs/>(b) <then/> <return/> <true/>; <end/>
<br /><span class="line-num">7</span>&#160;<tab/><return/> <false/>;
<br /><span class="line-num">8</span>&#160;<end/>
<br /><span class="line-num">9</span>&#160;
<br /><span class="line-num">10</span>&#160;<local/> a, b = 1,2;
<br /><span class="line-num">11</span>&#160;<print/>(greater(exchange(b,a)));
<br /><span class="line-num">12</span>&#160;<br /></ex>
<p>Программа напечатает <b>false</b>, поскольку наши переменные будут сначала поменяны местами.</p>
<p>Вышеописанный приём можно применять, если "внутренняя" функция (exchange в нашем примере) стоит на последнем
месте в списке параметров. Если это не так - из нее будет взят только один параметр.
В следующем примере одна из строчек программы выполнится правильно, а вторая сломается на арифметической операции:
</p>

<ex title="Передача многих параметров сразу - особенности" src="./src/ex037-return-to-func-bug.lua"><span class="line-num">1</span>&#160;<local/> a1,a2,a3,a4=1,2,3,4;
<br /><span class="line-num">2</span>&#160;
<br /><span class="line-num">3</span>&#160;<function/> sum4(a,b,c,d)
<br /><span class="line-num">4</span>&#160;<tab/><print/>(a+b+c+d);
<br /><span class="line-num">5</span>&#160;<end/>
<br /><span class="line-num">6</span>&#160;
<br /><span class="line-num">7</span>&#160;<function/> nothing(x,y,z)
<br /><span class="line-num">8</span>&#160;<tab/><return/> x,y,z;
<br /><span class="line-num">9</span>&#160;<end/>
<br /><span class="line-num">10</span>&#160;
<br /><span class="line-num">11</span>&#160;sum4(a1, nothing(a2,a3,a4)); <comm>-- печатает 10
</comm><br /><span class="line-num">12</span>&#160;sum4(nothing(a1,a2,a3), a4); <comm>-- выдаёт ошибку</comm><br /></ex>
<h2>Передача параметров по ссылке и по значению</h2>

<p>Обычные типы (строки, числа, логические переменные) в Lua передаются в функции по значению (то есть как обычно).
Параметр такого типа является локальной переменной внутри функции, его можно менять и при этом значение той переменной,
которую мы передавали в функцию, не изменится. Следующий пример это подтверждает:
</p>

<ex title="Передача параметров по значению" src="./src/ex038-by-val.lua"><span class="line-num">1</span>&#160;<function/> TryToChangeThem(int, float, bool, str)
<br /><span class="line-num">2</span>&#160;<tab/>int = -int;
<br /><span class="line-num">3</span>&#160;<tab/>float = float/2;
<br /><span class="line-num">4</span>&#160;<tab/>bool = <not/> bool;
<br /><span class="line-num">5</span>&#160;<tab/>str = str<concat/>str;
<br /><span class="line-num">6</span>&#160;<end/>
<br /><span class="line-num">7</span>&#160;
<br /><span class="line-num">8</span>&#160;<local/> i=1;
<br /><span class="line-num">9</span>&#160;<local/> f=5;
<br /><span class="line-num">10</span>&#160;<local/> b = <false/>;
<br /><span class="line-num">11</span>&#160;<local/> s = <str>"test"</str>;
<br /><span class="line-num">12</span>&#160;TryToChangeThem(i, f, b, s);
<br /><span class="line-num">13</span>&#160;<print/>(i, f, b, s);<br /></ex><p>Здесь будут напечатаны именно те значения, которые были изначально присвоены этим переменным.
Но есть и другие типы, для которых всё вышесказанное неверно. Среди тех, про которые мы уже что-то
знаем, - это таблицы и функции. Есть ещё два типа, про которые пока мне говорить не хочется,
чтобы не пугать читателя - с ними мы познакомимся позже.
</p>

<p>Что же касается таблиц, то приведем простой пример, хотя что такое таблица, я ещё детально не объяснял
(рекомендуется вспомнить <a href="#tables-example">вот этот пример</a>.
По-кухонному в данном примере можно считать, что таблица - это просто некоторая структура данных.
В нашем случае это будет пара чисел (скажем, точка на плоскости), а функция
по сути описывает некое геометрическое преобразование этой плоскости.
</p>

<ex title="Передача параметров по ссылке" src="./src/ex039-by-ref.lua"><span class="line-num">1</span>&#160;<function/> Transform(point)
<br /><span class="line-num">2</span>&#160;<tab/>point.x = point.x / 2;
<br /><span class="line-num">3</span>&#160;<tab/>point.y = point.y * 2;
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;
<br /><span class="line-num">6</span>&#160;p = {
<br /><span class="line-num">7</span>&#160;<tab/>x = 5,
<br /><span class="line-num">8</span>&#160;<tab/>y = 6
<br /><span class="line-num">9</span>&#160;};
<br /><span class="line-num">10</span>&#160;
<br /><span class="line-num">11</span>&#160;<print/>(p.x, p.y);
<br /><span class="line-num">12</span>&#160;Transform(p);
<br /><span class="line-num">13</span>&#160;<print/>(p.x, p.y);<br /></ex>
<p>Всё дело в том, что когда мы передаём в функцию таблицу, на самом деле туда передаётся только ее адрес,
никакого копирования данных не происходит. То же самое, кстати, происходит при операции присвоения на таблицах.
</p>

<p>Все эти тонкости надо понимать, чтобы не попортить свои же собственные данные (скажем, "скопировать" одну
таблицу в другую и потом начать ее менять, думая что копия-то сохранилась). В других языках выбор
типа передачи параметров лежит на пользователе (т.е. программисте), а тут - неявно в зависимости от типа,
и за этим вообще говоря надо следить. С той же осторожностью следует обращаться с функциями.
</p>

<h2>Функция как обычный тип данных</h2>

<p>Как уже было сказано выше, функция в Lua -- это такой же тип данных, как число или строка.
Поэтому допустимы такие конструкции:</p>

<ex title="Переменная-функция" src="./src/ex040-function-var.lua"><span class="line-num">1</span>&#160;<local/> sum = <function/>(x,y) <return/> x+y; <end/>
<br /><span class="line-num">2</span>&#160;<print/>(sum(1,2));<br /></ex>
<p>Здесь пока ничего необчного нет, кроме того что ключевое слово <b>function</b> и имя самой функции (sum)
поменялись местами. Теперь никто не мешает "скопировать" эту функцию в другую переменную (то есть на
самом деле просто дать ей альтернативное имя, так как никакого физического копирования кода не происходит),
например так:</p>

<ex>
local sum2 = sum;
</ex>

<p>После этого можно использовать функцию sum2 наравне с sum - она будет делать в точности то же самое.</p>

<p>А вот теперь мы напишем пример посложнее. Он будет осуществлять обычную сортировку массива, который
состоит либо из строк, либо из чисел. Причем правило сортировки такое: элемент a1 считается
меньше элемента a2, если:
<ul>
<li>a1 - число, а a2 -- строка;</li>
<li>a1 и a2 числа, и a1 меньше a2;</li>
<li>a1 и a2 строки, и длина a1 меньше длины a2;</li>
</ul>
Вот такая вот изощренная сортировка. Можно было бы написать одну функцию сравнения элементов, рассмотрев
в ней все три случая. Но мы поступим иначе - мы напишем три разных функции сравнения для каждого из случаев, 
и в зависимости от типов будем выбирать одну из трех.
</p>

<ex title="Мегасортировка" src="./src/ex041-mega-sort.lua"><span class="line-num">1</span>&#160;<local/> a={<str>"lua"</str>,100,1,<str>"scripting"</str>,2,45,23,<str>"is very fun!"</str>,52,<str>"super"</str>,56,<str>"a"</str>,4,6,70,<str>"power!"</str>,34,<str>"has"</str>};
<br /><span class="line-num">2</span>&#160;
<br /><span class="line-num">3</span>&#160;<function/> less_num(p,q)
<br /><span class="line-num">4</span>&#160;<tab/><if/> a[p] &lt; a[q] <then/> <return/> <true/>; <end/> <comm>-- number is always less than string
</comm><br /><span class="line-num">5</span>&#160;<tab/><return/> <false/>;
<br /><span class="line-num">6</span>&#160;<end/>
<br /><span class="line-num">7</span>&#160;
<br /><span class="line-num">8</span>&#160;<function/> less_str(p,q)
<br /><span class="line-num">9</span>&#160;<tab/><if/> <string/>.<len/>(a[p]) &lt; <string/>.<len/>(a[q]) <then/> <return/> <true/>; <end/>
<br /><span class="line-num">10</span>&#160;<tab/><return/> <false/>;
<br /><span class="line-num">11</span>&#160;<end/>
<br /><span class="line-num">12</span>&#160;
<br /><span class="line-num">13</span>&#160;<function/> less_mixed(p,q)
<br /><span class="line-num">14</span>&#160;<tab/><if/> <type/>(a[p]) <eq/> <type/>(a[q]) <then/> <error/>(<str>"shit happens"</str>); <end/>
<br /><span class="line-num">15</span>&#160;<tab/><if/> <type/>(a[p]) <eq/> <str>"number"</str> <then/> <return/> <true/>; <end/> <comm>-- number is always less than string
</comm><br /><span class="line-num">16</span>&#160;<tab/><return/> <false/>;
<br /><span class="line-num">17</span>&#160;<end/>
<br /><span class="line-num">18</span>&#160;
<br /><span class="line-num">19</span>&#160;<function/> getSortFunction(p, q)
<br /><span class="line-num">20</span>&#160;<tab/><if/> <type/>(a[p]) <eq/> <str>"number"</str> <and/> <type/>(a[q]) <eq/> <str>"number"</str> <then/>
<br /><span class="line-num">21</span>&#160;<tab/><tab/><return/> less_num;
<br /><span class="line-num">22</span>&#160;<tab/><elseif/> <type/>(a[p]) <eq/> <str>"string"</str> <and/> <type/>(a[q]) <eq/> <str>"string"</str> <then/>
<br /><span class="line-num">23</span>&#160;<tab/><tab/><return/> less_str;
<br /><span class="line-num">24</span>&#160;<tab/><end/>
<br /><span class="line-num">25</span>&#160;<tab/><return/> less_mixed;
<br /><span class="line-num">26</span>&#160;<end/>
<br /><span class="line-num">27</span>&#160;
<br /><span class="line-num">28</span>&#160;<function/> less(p,q) <comm>-- общая функция сравнения двух элементов (оператор &quot;меньше&quot;)
</comm><br /><span class="line-num">29</span>&#160;<tab/><local/> sort_function = getSortFunction(p, q); <comm>-- получаем функцию для сравнения
</comm><br /><span class="line-num">30</span>&#160;<tab/><if/> sort_function(p, q) <then/> <return/> <true/>; <end/>
<br /><span class="line-num">31</span>&#160;<tab/><return/> <false/>;
<br /><span class="line-num">32</span>&#160;<end/>
<br /><span class="line-num">33</span>&#160;
<br /><span class="line-num">34</span>&#160;<function/> getMin(s)
<br /><span class="line-num">35</span>&#160;<tab/><local/> l=#a;
<br /><span class="line-num">36</span>&#160;<tab/><local/> m = s;
<br /><span class="line-num">37</span>&#160;<tab/><for/> j=s+1,l <do/>
<br /><span class="line-num">38</span>&#160;<tab/><tab/><if/> less(j,m) <then/>
<br /><span class="line-num">39</span>&#160;<tab/><tab/><tab/>m=j;
<br /><span class="line-num">40</span>&#160;<tab/><tab/><end/>
<br /><span class="line-num">41</span>&#160;<tab/><end/>
<br /><span class="line-num">42</span>&#160;<tab/><return/> m;
<br /><span class="line-num">43</span>&#160;<end/>
<br /><span class="line-num">44</span>&#160;
<br /><span class="line-num">45</span>&#160;<function/> megaSort()
<br /><span class="line-num">46</span>&#160;<tab/><local/> l = #a;
<br /><span class="line-num">47</span>&#160;<tab/><for/> i=1,l <do/>
<br /><span class="line-num">48</span>&#160;<tab/><tab/><local/> m=getMin(i);
<br /><span class="line-num">49</span>&#160;<tab/><tab/><if/> m <neq/> i <then/>
<br /><span class="line-num">50</span>&#160;<tab/><tab/><tab/>a[m],a[i] = a[i],a[m];
<br /><span class="line-num">51</span>&#160;<tab/><tab/><end/>
<br /><span class="line-num">52</span>&#160;<tab/><end/>
<br /><span class="line-num">53</span>&#160;<end/>
<br /><span class="line-num">54</span>&#160;
<br /><span class="line-num">55</span>&#160;printArray = <function/>()
<br /><span class="line-num">56</span>&#160;<tab/><local/> s=<str>""</str>;
<br /><span class="line-num">57</span>&#160;<tab/><for/> i=1,#a <do/> s=s..<str>" "</str>..a[i]; <end/>
<br /><span class="line-num">58</span>&#160;<tab/><print/>(s);
<br /><span class="line-num">59</span>&#160;<end/>
<br /><span class="line-num">60</span>&#160;
<br /><span class="line-num">61</span>&#160;printArray();
<br /><span class="line-num">62</span>&#160;megaSort();
<br /><span class="line-num">63</span>&#160;printArray();
<br /><span class="line-num">64</span>&#160;<br /></ex>
<p>Когда мы дойдем до изучения таблиц, мы узнаем, что всё то же самое можно было бы сделать гораздо короче и красивее.
Мне просто хотелось привести пример относительно большой содержательной программы. 
На этом мы завершаем знакомство с функциями и переходим к самому интересному - таблицам.
</p>

<h1>Таблицы и мета-таблицы</h1>

<p>Начнем с маленького в меру лирического отступления о том, откуда вообще берется такая суета вокруг таблиц
и почему они важны. Любой язык программирования (точнее, сама программа) в известном смысле призван моделировать те процессы,
которые происходят вокруг нас, систематизировать и перерабатывать какие-то данные, которые у нас имеются, и т.д.
Так вот когда данных становится много и они однотипны, образуются последовательности, таблицы, массивы, матрицы,
кубы и так далее. Причем очень часто наши данные не имеют каких-либо ярко выраженных "номеров", которые можно было бы
использовать в качестве индексов массива. Или же, номера имеются, но совсем не по порядку или же среди них встречаются
вещественные (т.е. не целые) значения. Обычного массива в этом случае не организуешь - он будет либо слишком
разреженным, либо неудобным для использования. Каков же выход из этой ситуации? Одно из решений, которое резко
упрощает нашу модель - это ассоциативный массив, в котором ключом (индексом) может являться любая сущность, для
которой определена операция сравнения (а для хорошей быстрой реализации - ещё и оператор "А меньше Б").
В ассоциативных массивах (то есть std::map-ах в терминологии С++) мы получаем возможность нумеровать элементы
любым классом, для которого определены вышеупомянутые операции. Почти то же самое мы имеем и в Lua.
Наиболее часто приходится индексировать таблицы числами и строками (а если немного слукавить, то по сути 
других базовых типов и не бывает в природе).</p>

<p>Отметим также и такой немаловажный момент: эффективная реализация таблиц (ассоциативных массивов) позволяет удобно
работать с базами данных, поскольку там структура хранения данных именно такова - у большинства таблиц базы есть
ключ (или ключи, что не так важно), которому соответствует ровно одна строка (row) таблицы. Чтобы написать на С++
программу, в которой можно было бы легко и удобно оперировать с записями в базе, нам пришлось бы как минимум все
таблицы нашей базы реализовать в виде классов. А в Lua этого делать не надо - всё уже сделано до нас! Просто берем
и пользуемся. Кстати, библиотека для Lua, которая реализует работу с БД, тоже существует (LuaSQL), и она в разы проще,
чем аналогичный API для С++.
</p>

<h2>Таблицы</h2>

<p>Если читатель ещё не забыл <a href="#tables">параграф о таблицах</a> в разделе "Типы данных", то он наверняка помнит,
что новая пустая таблица конструируется с помощью фигурных скобок:</p>

<ex>tab={};</ex>

<p>Отметим, что в данном случае в памяти создаётся новый объект и переменной tab присваивается указатель на него.
Если мы захотим присвоить одну таблицу другой подобным присвоением - в этом случае мы получим не копию,
а два указателя на одно и то же место.
</p>

<p>Если же мы знаем, чем заполнять таблицу, можно написать и так:</p>

<ex>tab={"text", 1, 2, "other text", 3};</ex>

<p>В этом случае элементы будут автоматически пронумерованы числами, начиная с 1. Давайте в этом наглядно убедимся
с помощью простой программы:</p>

<ex title="Автонумерация" src="./src/ex042-tables-auto-index.lua"><span class="line-num">1</span>&#160;tab={<str>"text"</str>, 1, 2, <str>"other text"</str>, 3};
<br /><span class="line-num">2</span>&#160;<for/> i,v <in/> <pairs/>(tab) <do/>
<br /><span class="line-num">3</span>&#160;<tab/><print/>(i, v);
<br /><span class="line-num">4</span>&#160;<end/><br /></ex>
<p>Выполните её, и убедитесь, что порядок элементов сохранился, а индексы будут от 1 до 5. Фактически, тут мы
получили обычный массив. Для полной ясности надо разобрать подобнее оператор <b>for</b> и конструкцию <b>pairs</b>,
чему посвящен следующий параграф, а пока что посмотрим, какие ещё есть способы инициализации таблиц.
</p>

<h3>Особенности национальной индексации</h3>

<p>Индексы можно указывать явно, в данном примере результат будет в точности такой же как и в предыдущей программе:</p>

<ex title="Явная нумерация" src="./src/ex042-tables-manual-index.lua"><span class="line-num">1</span>&#160;tab={
<br /><span class="line-num">2</span>&#160;<tab/>[1]=<str>"text"</str>,
<br /><span class="line-num">3</span>&#160;<tab/>[2]=1,
<br /><span class="line-num">4</span>&#160;<tab/>[3]=2,
<br /><span class="line-num">5</span>&#160;<tab/>[4]=<str>"other text"</str>,
<br /><span class="line-num">6</span>&#160;<tab/>[5]=3
<br /><span class="line-num">7</span>&#160;}
<br /><span class="line-num">8</span>&#160;<br /></ex>
<p>А вот пример с индексами разных типов:</p>

<ex title="Смешанная индексация" src="./src/ex042-table-mixed-init.lua"><span class="line-num">1</span>&#160;tab={
<br /><span class="line-num">2</span>&#160;<tab/>[1]=<str>"text"</str>,
<br /><span class="line-num">3</span>&#160;<tab/>[2]=1,
<br /><span class="line-num">4</span>&#160;<tab/>[<str>"key"</str>]=<str>"value"</str>
<br /><span class="line-num">5</span>&#160;};
<br /><span class="line-num">6</span>&#160;<for/> i, v <in/> <pairs/>(tab) <do/>
<br /><span class="line-num">7</span>&#160;<tab/><print/>(<str>"Key is: "</str>, i, <str>"Value is: "</str>, v, <type/>(i));
<br /><span class="line-num">8</span>&#160;<end/><br /></ex>
<p>Однако лучше не злоупотреблять смешанной индексацией без необходимости, поскольку это может привести к ошибкам.
Засада заключается в том, что Lua <b>различает строковые и числовые индексы</b>, и поэтому t[1] не равно t["1"].
Вот пример:</p>

<ex title="Засада с типами" src="./src/ex042-table-types-matching.lua"><span class="line-num">1</span>&#160;tab_auto={<str>"value"</str>};
<br /><span class="line-num">2</span>&#160;<print/>(tab_auto[1], tab_auto[<str>"1"</str>]);
<br /><span class="line-num">3</span>&#160;
<br /><span class="line-num">4</span>&#160;tab_man={[1]=<str>"value"</str>};
<br /><span class="line-num">5</span>&#160;<print/>(tab_man[1], tab_man[<str>"1"</str>]);
<br /><span class="line-num">6</span>&#160;
<br /><span class="line-num">7</span>&#160;tab_str={[<str>"1"</str>]=<str>"value"</str>};
<br /><span class="line-num">8</span>&#160;<print/>(tab_str[1], tab_str[<str>"1"</str>]);<br /></ex>
<p>Программа печатает вот что:</p>

<ex>
value	nil<br/>
value	nil<br/>
nil	value<br/>
</ex>

<p>Таким образом, правило простое: какой индекс мы выбрали - по такому и следует обращаться, в случае индексов таблиц
автоматической конвертации типов нет.</p>

<p>Тут стоит сказать ещё про одну засаду. Следующий пример относится скорее к категории антипримеров,
то есть "как не надо делать". А именно, не стоит использовать одновременно явную и неявную индексацию массивов.</p>

<ex title="Ошибка инициализации таблицы" src="./src/ex042-table-mixed-index-bug.lua"><span class="line-num">1</span>&#160;tab={
<br /><span class="line-num">2</span>&#160;<tab/>[1]=<str>"number one..."</str>,
<br /><span class="line-num">3</span>&#160;<tab/>[2]=<str>"number two..."</str>,
<br /><span class="line-num">4</span>&#160;<tab/><str>"number three..."</str>,
<br /><span class="line-num">5</span>&#160;<tab/><str>"...etc"</str>
<br /><span class="line-num">6</span>&#160;}
<br /><span class="line-num">7</span>&#160;<for/> i, v <in/> <pairs/>(tab) <do/>
<br /><span class="line-num">8</span>&#160;<tab/><print/>(<str>"Key: "</str>, i, <str>"Val: "</str>, v, <str>"Type: "</str>, <type/>(i));
<br /><span class="line-num">9</span>&#160;<end/><br /></ex>
<p>В этой программе первые два элемента просто погибнут, так как они будут замещены автоматически
пронумерованными 3-м и 4-м элементом. В итоге таблица будет из 2 строк, а не из четырех.
</p>

<h3>Таблицы как структуры</h3>

<p>Есть ещё один замечательный способ задания индексов таблиц, который наверняка понравится любителям ООП.
Можно использовать такую запись:</p>

<ex title="Структуры" src="./src/ex043-table-as-struct.lua"><span class="line-num">1</span>&#160;complex = {
<br /><span class="line-num">2</span>&#160;<tab/>re=1,
<br /><span class="line-num">3</span>&#160;<tab/>im=2
<br /><span class="line-num">4</span>&#160;};
<br /><span class="line-num">5</span>&#160;<print/>(complex.re, complex.im);
<br /><span class="line-num">6</span>&#160;<print/>(complex[<str>"re"</str>], complex[<str>"im"</str>]);
<br /><span class="line-num">7</span>&#160;<br /></ex>
<p>В двух строках будет выведено одно и то же, так как запись table.key и table["key"] означает одно и то же.
Согласитесь, что первая конструкция намного симпатичнее второй.</p>

<h3>for, pairs и ipairs</h3>

<p>Для перечисления элементов таблиц нам уже не годится арифметический цикл for, так как вместо номеров (индексов)
могут быть и строки, и таблицы, и числа, и функции. Для таких случаев есть оператор <b>in</b>, который умеет
перечислять все элементы массива или таблицы в некотором порядке. А в каком именно порядке - это может зависеть
от реализации нашего интерпретатора, стандарта на этот счёт не существует. Можно только лишь гарантировать, что
он переберёт <i>все</i> элементы. Множество элементов, по которому мы будем бегать, можно получить с помощью оператора
<b>pairs</b>. Он будет выдавать нам по очереди все пары [индекс, значение] нашей таблицы
(а точнее говоря - [ключ, значение], так как в случае строковых ключей таблицы слово "индекс" не очень уместно).</p>

<ex title="Распечатка всех значений таблицы" src="./src/ex043-table-print.lua"><span class="line-num">1</span>&#160;tab={<str>"it"</str>, <str>"is"</str>, <str>"a"</str>, <str>"Table"</str>};
<br /><span class="line-num">2</span>&#160;<for/> i, v <in/> <pairs/>(tab) <do/>
<br /><span class="line-num">3</span>&#160;<tab/><print/>(<str>"Key is: "</str>, i, <str>"Value is: "</str>, v);
<br /><span class="line-num">4</span>&#160;<end/><br /></ex>
<ex title="Распечатка всех значений таблицы (вывод)" src="./src/ex043-table-print-output.txt"><span class="line-num">1</span>&#160;Key is: <tab/>1<tab/>Value is: <tab/>it
<br /><span class="line-num">2</span>&#160;Key is: <tab/>2<tab/>Value is: <tab/>is
<br /><span class="line-num">3</span>&#160;Key is: <tab/>3<tab/>Value is: <tab/>a
<br /><span class="line-num">4</span>&#160;Key is: <tab/>4<tab/>Value is: <tab/>Table<br /></ex>
<p>Я думаю, теперь читателю стали полностью понятны примеры, которые приводились выше в предыдущих параграфах.</p>

<p>Если мы захотим перебрать только числовые индексы таблиц, нам поможет конструкция <b>ipairs</b>.
Работает она совершенно аналогично:</p>

<ex title="Распечатка значений таблицы с числовыми индексами" src="./src/ex044-table-print-ipairs.lua"><span class="line-num">1</span>&#160;tab={
<br /><span class="line-num">2</span>&#160;<tab/>[1]=<str>"text"</str>,
<br /><span class="line-num">3</span>&#160;<tab/>[<str>"key"</str>]=<str>"value"</str>,
<br /><span class="line-num">4</span>&#160;<tab/>[2]=<str>"other text"</str>,
<br /><span class="line-num">5</span>&#160;<tab/>[3]=3
<br /><span class="line-num">6</span>&#160;}
<br /><span class="line-num">7</span>&#160;<print/>(<str>"Number Pairs"</str>);
<br /><span class="line-num">8</span>&#160;<for/> i, v <in/> <ipairs/>(tab) <do/>
<br /><span class="line-num">9</span>&#160;<tab/><print/>(<str>"Key is: "</str>, i, <str>"Value is "</str>, v);
<br /><span class="line-num">10</span>&#160;<end/>
<br /><span class="line-num">11</span>&#160;<print/>(<str>"All Pairs"</str>);
<br /><span class="line-num">12</span>&#160;<for/> i, v <in/> <pairs/>(tab) <do/>
<br /><span class="line-num">13</span>&#160;<tab/><print/>(<str>"Key is: "</str>, i, <str>"Value is "</str>, v);
<br /><span class="line-num">14</span>&#160;<end/><br /></ex>
<h3>Размер таблицы, количество элементов, обход всех элементов</h3>

<p>Вообще говоря, понятие "размера" в Lua применимо только к массивам, то есть к таблицам с числовыми индексами.
Размером массива tab называется индекс i максимального элемента, такого что tab[i] ~= nil, а tab[i+1] = nil
(и при этом все элементы с меньшими номерами также не нулевые). Одним словом, размер - это длина непрерывной
последовательности непустых индексов от начала масива. Размер можно получить с помощью операции "#":
</p>

<ex title="Получение размера таблицы" src="./src/ex045-table-size.lua"><span class="line-num">1</span>&#160;tab={<str>"array"</str>, <str>"length"</str>, <str>"sample"</str>};
<br /><span class="line-num">2</span>&#160;<local/> size=#tab;
<br /><span class="line-num">3</span>&#160;<print/>(size);<br /></ex>
<p>Что будет напечатано? Конечно же, число 3. А вот пример похитрее:</p>

<ex title="Получение размера таблицы с дыркой" src="./src/ex046-table-with-hole-size.lua"><span class="line-num">1</span>&#160;tab={[1]=<str>"array"</str>, [2]=<str>"length"</str>, [3]=<str>"sample"</str>, [5]=<str>"hole between indexes"</str>};
<br /><span class="line-num">2</span>&#160;<print/>(#tab);<br /></ex>
<p>В соответствии с определением длины, тут тоже будет напечатано число 3.</p>

<p>Для произвольной таблицы длина вообще не определена. Узнать количество элементов в ней можно,
лишь обойдя ее полностью по уже изученной схеме циклом for.
</p>

<h3>Стандартная библиотека table</h3>

<p>Для удобной работы с массивами в Lua есть стандартная библиотека table. Там есть весьма часто используемые
функции, например добавление и удаление элементов, сортировка и прочее. Следующий пример считывает построчно
файл программы (то есть самой себя) и складывает в массив, а потом печатает ее:</p>

<ex title="Нечестный способ распечатать собственный текст" src="./src/ex047-self-print-cheat.lua"><span class="line-num">1</span>&#160;<local/> selftext=<brackets/>;
<br /><span class="line-num">2</span>&#160;<for/> line <in/> io.lines(<arg/>[0]) <do/>
<br /><span class="line-num">3</span>&#160;<tab/><table/>.<insert/>(selftext, line);
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;<for/> _,line <in/> <pairs/>(selftext) <do/>
<br /><span class="line-num">6</span>&#160;<tab/><print/>(line);
<br /><span class="line-num">7</span>&#160;<end/><br /></ex>
<p>Функция table.insert имеет два обязательных параметра (таблицу и новый элемент), и необязательный параметр position,
указывающий куда этот элемент вставлять. Если он не указан, добавление происходит в конец таблицы.
Вот та же самая программа, печатающая себя вверх ногами:
</p>

<ex title="Вверх дном" src="./src/ex048-self-print-rotated.lua"><span class="line-num">1</span>&#160;<local/> selftext=<brackets/>;
<br /><span class="line-num">2</span>&#160;<for/> line <in/> io.lines(<arg/>[0]) <do/>
<br /><span class="line-num">3</span>&#160;<tab/><table/>.<insert/>(selftext, 1, line);
<br /><span class="line-num">4</span>&#160;<end/>
<br /><span class="line-num">5</span>&#160;<for/> _,line <in/> <pairs/>(selftext) <do/>
<br /><span class="line-num">6</span>&#160;<tab/><print/>(line);
<br /><span class="line-num">7</span>&#160;<end/><br /></ex>
<p>Помните, в самом начале у нас была программа, печатающая простые числа?
Вот ее более быстрая реализация с помощью таблиц:
</p>

<ex title="Ускоренные простые числа" src="./src/ex049-primes-advanced.lua"><span class="line-num">1</span>&#160;<local/> primes={2,3};
<br /><span class="line-num">2</span>&#160;<local/> n=10000;
<br /><span class="line-num">3</span>&#160;
<br /><span class="line-num">4</span>&#160;<function/> isPrime(x)
<br /><span class="line-num">5</span>&#160;<tab/><for/> _,p <in/> <pairs/>(primes) <do/>
<br /><span class="line-num">6</span>&#160;<tab/><tab/><if/> x%p <eq/> 0 <then/> <return/> <false/>; <end/>
<br /><span class="line-num">7</span>&#160;<tab/><tab/><if/> p &gt; x/2 <then/> <break/>; <end/>
<br /><span class="line-num">8</span>&#160;<tab/><end/>
<br /><span class="line-num">9</span>&#160;<tab/><return/> <true/>;
<br /><span class="line-num">10</span>&#160;<end/>
<br /><span class="line-num">11</span>&#160;
<br /><span class="line-num">12</span>&#160;<for/> i = 5,n,2 <do/>
<br /><span class="line-num">13</span>&#160;<tab/><if/> isPrime(i) <then/> <table/>.<insert/>(primes,i); <end/>
<br /><span class="line-num">14</span>&#160;<end/>
<br /><span class="line-num">15</span>&#160;
<br /><span class="line-num">16</span>&#160;<for/> i,v <in/> <pairs/>(primes) <do/>
<br /><span class="line-num">17</span>&#160;<tab/><print/>(v);
<br /><span class="line-num">18</span>&#160;<end/>
<br /><span class="line-num">19</span>&#160;<br /></ex>
<p>То, что оно работает быстрее, предлагается проверить читателю. А ещё ему предлагается написать
аналогичный код, скажем, на С++ и посмотреть, на сколько ему удастся обогнать Lua.
Таблицы реализованы в Lua очень эффективно, и проигрывают С-шным реализациям не так уж сильно
(иногда "всего" в 2-3 раза, что для интерпретируемого языка, согласитесь, очень нехило).
У других скриптовых языков, например у Python в среднем этот коэффициент существенно выше, хотя его спасает очень
богатая стандартная библиотека, которая само собой реализована на С и потому "кишки" работают быстро.
</p>

<p>Ещё одна операция, которая часто используется в прикладных программах, - это сортировка.
Lua умеет сортировать таблицы, если ему объяснить, как сравнивать два элемента. Объяснение делается
с помощью функции сравнения, которую надо передать стандартной библиотеке.
Если ее не указать, он будет пытаться сравнивать элементы стандартным оператором &lt;, и в простых случаях оно даже сработает.
Вот примеры:</p>

<ex title="Сортировка массива" src="./src/ex050-table-sort.lua"><span class="line-num">1</span>&#160;<local/> array_int={3,45,6,234,653,2,51,43,32};
<br /><span class="line-num">2</span>&#160;<table/>.sort(array_int);
<br /><span class="line-num">3</span>&#160;<print/>(<table/>.concat(array_int, <str>', '</str>));
<br /><span class="line-num">4</span>&#160;<local/> array_string={<str>"lua"</str>, <str>"is"</str>, <str>"a"</str>, <str>"great"</str>, <str>"language"</str>};
<br /><span class="line-num">5</span>&#160;<table/>.sort(array_string);
<br /><span class="line-num">6</span>&#160;<print/>(<table/>.concat(array_string, <str>', '</str>));<br /></ex>
<h2>Мета-таблицы</h2>

<!--
<p>Основной прикол заключается в том, что в качестве индексов таблиц можно использовать всё что угодно:
числа, строки, а также другие таблицы... и что самое интересное, в одной таблице
можно использовать всё это одновременно. Но об этом позже.
</p>

<p>Да, кстати. Что такое размер массива? Это индекс <i>последнего</i> элемента. А что такое последний элемент?
Это элемент с наибольшим номером, для которого <b>a[i]</b> не равно <b>nil</b>, а <b>a[i+1]</b> уже равно <b>nil</b>.
-->


<nav>
<back ref="index.xml">Главная страница</back>
</nav>
</div>
</body>
</doc>