Продолжение прошлой статьи. Поехали. --=========================
§14. Таблицы.
Таблицы в целом — самый важный тип данны в Lua.
-------------------------------
§14.1. Массивы.
Первое, что рассмотрим, — массивы. Массивы — это таблицы с числовой индексацией. Массив начинается с его названия, потом ставится равно и в фигурных скобках значения. Каждый элемент массива пишется в кавычках и разделяется запятой.
Синтаксис:
Код
... = {...};
Самый простой массив выглядит так:
Код
m = {};
«Заполнять» массивы можно так:
Код
m = {"one","two","three",};
После последнего элемента запятая не обязательна.
А можно и так:
Код
m[1] = "one"; m[2] = "two"; m[3] = "three";
Индексация массивов — это следующий параграф.
-------------------------------
§14.1.1. Индексация массивов.
Индексация массивов в Lua начинается не с нуля, как в некоторых других языках (в том же C), а с единицы.
Вот эта запись:
Код
m = {"one","two","three",};
Полностью эквивалентна этой:
Код
m = {[1] = "one",[2] = "two",[3] = "three",};
Подобная индексация нежелательна:
Код
m = {[1] = "one",[3] = "three",};
Почему? Это следующий параграф.
Но если надо, можно так:
Код
m = {[1] = "one",[2] = nil,[3] = "three",};
-------------------------------
§14.1.2. Определение длины массива.
Оператор длины массива возвращает наибольший индекс элементов массива. В более старых версиях Lua этим оператором служит функция table.getn(), в более новых же можно использовать есть оператор «#», функцию же можно по-прежнему использовать.
В общем, чтобы оператор длины работал корректно, нужно указывать все индексы правильно, или не указывать вообще, — Lua это сам сделает.
-------------------------------
§14.1.3. Обращение к элементам массива.
Обращение к элементам массива происходит так:
Код
m = {"one","two","three",};
if m[1] then print(m[1]); -- "one" end if m[2] then print(m[2]); -- "two" end if m[3] then print(m[3]); -- "three" end
Пишется название массива, затем в квадратных скобках указывается его индекс.
-------------------------------
§14.1.4. Цикл обхода всех элементов массива.
Вот, собственно, один из двух циклов, упомянутый в §10.5.
Для обхода всех элементов массива используется расширенный арифметический цикл for вместе с переменной ipairs.
Синтаксис:
Код
for ...,... in ipairs(...) do ... end
То, что перед запятой, — индекс массива, а после — его значение (для примера ниже значение первого индекса — "one").
Пример:
Код
m = {"one","two","three",}; for i,v in ipairs(m) do print(i.." is "..v); end
Как и в случае с арифметическим циклом, две эти переменные являются локальными и могут принимать любые другие значения:
Код
for h,z in ipairs(m) do ... end
Иногда в получении индекса либо значения нет необходимости, в таком случае, переменная заменяется на подчёркивание:
Код
for _,v in ipairs(m) do ... end
-------------------------------
§14.1.4.1. Обход элементов массива иными способами.
Для обхода все элементов можно и не пользоваться ipairs и for .. in, а просто воспользоваться арифметическим for и оператором длины:
Код
for i=1,table.getn(m) do ... end
В качестве индекса используется, как понятно, переменная i.
Только стоит учесть, что при использовании этого варианта получение значения массива будет недоступным.
А вот может случиться такая ситуация, что нескольким (но не всем) элементам массива необходимо будет присвоить одно и то же значение. Можно, конечно, воспользоваться примитивными методами, типа:
Код
m[5] = nil; m[6] = nil;
И так далее. Но намного быстрее воспользоваться арифметическим for:
Код
for i=5,10 do m[i] = nil; end
Для всех элементов можно по стандарту:
for i,_ in ipairs(m) do m[i] = nil; end
Тут уже кому как.
-------------------------------
§14.1.5. Массивы внутри массивов.
Если есть необходимость в этом, внутри пары фигурных скобок создаётся ещё одна пара (просто фигурные скобки, без названия), и туда как обычно записываются элементы нового массива.
Пример:
Код
m = {{"one","half",},"two","three",};
Обращение к элементам массива, который внутри другого массива, происходит так: сначала в квадратных скобках пишется индекс внешнего массива, в котором расположен внутренний, затем уже так же индекс элемента внутреннего массива:
Так можно создавать огромное количество массивов, каждый из которых будет внутри предыдущего:
Код
m = {{{{{nil}}}}};
print(m[1][1][1][1][1]); -- nil
-------------------------------
§14.2. Таблицы.
Таблицы — это набор пар «ключ — значение». Конструкция такая же, как и у массивов.
Вот пример:
Код
t = { one = 1, two = 2, three = 3, };
В отличии от массивов элементы таблицы таблицы индексируются переменными. А значением может быть абсолютно любой тип данных Lua, да и вообще всё что угодно:
Код
t = { color = "black", number = 1.2, param = true, };
Как уже было сказано выше, значением таблиц могут быть и числа, и булевые значения (true, false), и функции, и строки, и таблицы, и массивы, и даже nil. Для отделения типов данных друг от друга будет удобно использовать точку с запятой вместо обычной запятой:
l = { one = 1, two = 2, three = 3, }; print(l.one); -- 1 print(l.two); -- 2 print(l.three); -- 3
Когда в таблице таблица, обращение происходит так:
Код
t = { t1 = { one = 1, two = 2, three = 3, }, }; print(t.t1.one); -- 1
Когда в таблице массив, обращаться можно так:
Код
t = { t1 = {"one","two","three",}, }; print(t.t1[1]); -- "one"
Ну и понятно, что если в таблице есть массив, внутри которого массив, обращаться можно так:
Код
t = { t1 = {{"one","half",},"two","three",}, }; print(t.t1[1][2]); -- "half"
Для таблиц понятия «длина» как такового нет, так что использовать соответствующего оператора для таблиц нельзя.
-------------------------------
§14.2.2. Цикл обхода элементов таблицы.
Что это — обьяснять не надо. Для обхода элементов таблицы используется pairs, вместо ipairs. И обычно вместо переменной i (index) используется k (key) (но можно, естественно, писать свои названия).
Синтаксис:
Код
for k,v in pairs(...) do ... end
Пример:
Есть таблица со списком оружия и его уроном в процентах. Надо присвоить всему оружия нулевой урон:
for k,_ in pairs(Weapons) do local w = Weapons; w[k] = 0; end
-------------------------------
§14.2.3. Функции в таблицах.
Сразу создать функцию в таблице, похоже нельзя. Но если такое необходимо, это можно сделать следующим образом:
Код
tab = {};
function tab:func(a,b) print(a+b); end
tab:func(2,2); -- 4
-------------------------------
§14.3. Функции для работы с таблицами.
Все они начинаются с «table.» (от англ. «table» — ‘таблица’). Вот все они:
table.concat(table [, sep [, i [, j]]]):
Задан массив, в котором все элементы — строки или числа, возвращает table[i]..sep..table[i+1] ··· sep..table[j]. Значение по умолчанию для sep — пустая строка, значение по умолчанию для i — 1, а для j — длина таблицы. Если i больше j, функция возвращает пустую строку.
table.insert(table, [pos,] value):
Вставляет элемент value в позицию pos в table, сдвигая вверх остальные элементы. Значение по умолчанию для pos равно n+1, где n — длина таблицы, т. о., вызов table.insert(t,x) добавляет x в конец таблицы t. Только для массивов.
Пример:
Код
m = {"one","two","three",}; table.insert(m,"four");
print(m[4]); -- four
table.maxn(table):
То же, что и table.getn и #.
table.remove(table [, pos]):
Удаляет из table элемент в позиции pos, сдвигая вниз остальные элементы, если это необходимо. Возвращает значение удаленного элемента. Значение по умолчанию для pos — n, где n — длина таблицы, т. о., вызов table.remove(t) удаляет последний элементы таблицы t. (Примечание: использование insert-remove со значениями по умолчанию позволяет работать с таблицей как со стандартным LIFO – стеком) Только для массивов.
Пример:
Код
m = {"one","two","three","four"}; table.remove(m);
print(m[4]); -- nil
table.sort(table [, comp]):
Сортирует элементы таблицы в заданном порядке внутри таблицы, начиная с table[1] и заканчивая table[n], где n — длина таблицы. Если параметр comp задан, то он должен быть функцией, которая для двух получаемых параметров возвращает true, если первый из них меньше второго (т. о., not comp(a[i+1],a[i]) будет верно для любого i давать true после окончания сортировки). Если comp не задан, то вместо него будет использован стандартынй оператор Lua «<».
Алгоритм сортировки не стабилен; в том смысле, что равные элементы могут быть переставлены в процессе сортировки.
Также ещё существуют такие полезные функции для массивов:
next():
Возвращает следующей индекс массива после указанного и соответствующее ему значение.
Пример:
Код
m = {"one","two","three","four","five"};
print(next(m)); -- 1 one print(next(m,1)); -- 2 two print(next(m,table.getn(m))); -- nil
unpack():
Возвращает либо все значения массива, либо от одного индекса и до другого.
Пример:
Код
m = {"one","two","three","four","five"};
print(unpack(m)); -- one two three four five print(unpack(m,2,3)); -- two three print(unpack(m,1,4)); -- one two three four
rawget():
Возвращает значение указанного индекса массива.
Пример:
Код
m = {"one","two","three","four","five"};
print(rawget(m,3)); -- three print(rawget(m,table.getn(m))); -- five
Вместо этого можно просто написать так:
Код
print(m[3]); -- three print(table.getn(m)); -- five
rawset():
Присваивает указанному индексу массива новое указанное значение.
Код
m = {"one","two","three","four","five"};
rawset(m,1,"oneone");
print(m[1]); -- oneone
Вместо этого можно просто написать так:
Код
m[1] = "oneone"
print(m[1]); -- oneone
--========================= §15. Функции ввода-вывода.
Все эти функции начинаются с «io.» (сокр. от англ. «input-output» — ‘ввод-вывод’). Главное применение — изменение внутреннего содержания файла непросредственно из Lua-скрипта. Вот четыре функции, которые понадобятся для этого:
io.open():
Открывает файл по указанному пути в указанном режиме. Режимов всего три: «r» — режим чтения. Данный режим используется как режим по умолчанию. То есть, если не указать режим, файл откроется в данном режиме; «w» — режим записи. Вся имеющаяся ранее информация стирается; «a» — режим дозаписи в конец файла. Вся имеющаяся ранее информация сохраняется. Путь в свою очередь пишется в кавычках; название файла обязательно должно иметь расширение. Если в указанной директории не существует такого файла, он будет создан.
file:write():
Записывает в указанный файл указанные значения. Ими должны быть только строки, числа и управляющие последовательности. file — переменная, открывающая файл (ниже всё станет понятно).
file:flush():
Сохраняет сделанные изменения в указанном файле.
io.close():
Закрывает указанный файл.
Пример:
Нужно дописать в конец файла script.lua, расположенного в папке data, несколько строк:
Код
-- окрываем наш файл в режиме дозаписи в конец файла local f = io.open("data/script.lua","a");
-- создаём массив из строк, которые необходимо добавить в конец нашего файла local ns = { "string1", "string2", "string3", "string4", "string5", };
-- сначала записываем первую строку, чтобы между ней и записями в файле была отступлена пустая строка f:write("\n".."\n"..ns[1].."\n"); -- затем записываем остальные строки кроме последней (её, как и первую, нужно отформатировать отдельно) for i=2,(table.getn(ns))-1 do f:write(ns[i].."\n"); end -- ну и записываем последнюю строку f:write(ns[table.getn(ns)]);
-- сохраняем сделанные изменения f:flush();
-- закрываем наш файл io.close(f);
После открытия файла в конце будет следующее:
Код
[прочие строки, уже имеющиеся в файле]
string1 string2 string3 string4 string5
-------------------------------
§15.1. Ещё несколько полезных функций.
io.lines():
Открывает указанный файл в режиме чтения, считывает из него все имеющиеся в нём в строке и возвращает каждую отдельно.
Пример:
Код
local f = io.open("data/script.lua");
for line in io.lines(f) do print(tostring(line)); end
После конца цикла эта функция автоматический закрывает файл.
file:lines():
То же, что и io.lines, но не закрывает файл file после окончания цикла.
file:seek():
Получает и выставляет в файле позицию, заданную первым аргументом, им может быть:
"set" — начало файла; "cur" — текущая позиция; "end" — конец файла.
Вторым аргументом (число) можно приплюсовать к первому дополнительное количество строк, которое нужно отсчитать от выбранной позиции.
Пример:
Код
f:seek("set",0); -- позиция выставлена в самое начало файла f:seek("set",1); -- позиция выставлена во второй строке от начала файла вниз
--========================= §16. Функции операционной системы.
Все эти функции начинаются с «os.» (сокр. от англ. «operation system» — ‘операционная система’) Вот некоторые из них:
os.clock():
Возвращает примерное количество времени (в секундах), которое программа выполнялась на CPU.
os.date():
Возвращает дату, отформатированную в соответствии с заданным форматом. Если аргумент time передается функции, то должно быть отформатировано «время» (os.time). В противном случае, параметр date используется для форматирования текущего времени. Если параметр format начинается с «!», то время форматируется в соответствии с универсальным глобальным временем (по Гринвичу). После этого опционального символа, если format равен «*t», то date возвращает таблицу со следующими полями: year (год, четыре цифры), month (месяц, 1—12), day (день, 1—31), hour (час, 0—23), min (минуты, 0—59), sec (секунды, 0—61), wday (день недели, воскресенью соответствует 1 и так адлее), yday (день года), и isdst (флаг дневного времени суток, тип boolean). Если format не равен «*t», то функция date возвращает дату в виде строки, отформатированной в соответствии с правилами функции C strftime. При вызове без аргументов возвращают дату, во время которой была вызвана данная функция, в соответствии с установленными датой и временем оперционной системы, в следующем формате: MM/DD/YYYY HH:MM:SS.
os.difftime():
Возвращает время, прошедшее от первого аргумента до второго, в секундах. На самом деле функция просто возвращает значение первого аргумента минус значение второго аргумента.
Удаляет указанную пупку или файл из указанной директории. Если удаляется папка, она должна быть пустой. Если функция не может произвести удаление, она возвращает nil и сообщение об ошибке.
Пример:
Код
os.remove("data/script.lua"); -- файл удалён os.remove("data"); -- папка, если она пустая, удалена
os.rename():
Переименовывает указанную папку или файл (первый аргумент) в новое имя (второй аргумент). Если функция не может произвести переименовывание, она возвращает nil и сообщение об ошибке.
Пример:
Код
os.remove("data/script.lua","data/script1.lua"); -- файл переименован в script1.lua os.remove("data","data1"); -- папка переименована в data1
os.tmpname():
Возвращает строку с именем файла, который может быть использован в качестве временного файла. Файл должен быть явно открыт до использования и явно удален, если больше не будет нужен. --========================= Автор статьи: TranZit. Для написания статьи были использованы и изменены материалы с Lua.ru.
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Lua. Туториал для начинающих. Часть 4», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]