![]() |
Программирование на Lua |
![]() |
Часть I. Язык Глава 2. Типы и Значения |
Тадлицы реализуются массивами соответствий (ассоциативными массивами). Ассоциативный массив - это массив, который может индексироваться не только числом, но также и строкой или любым другим значением языка, исключая nil. Более того, таблицы не имеют фиксированного размера; вы можете динамически добавлять в таблицу столько элементов, сколько хотите. Таблицы являются не только основным способом (in fact, the only) структурирования данных в Lua, но и самым мощным. Тадлицы используются для представления обычных массивов, символьных таблиц, множеств, записей, очередей и других структур данных , как простой, единообразный и эффективный путь. Lua также использует таблицы для представления пакетов. Когда мы пишем io.read
, мы подразумеваем "элемент read
в пакете io
". Для Lua это значит "индексирование таблицы io
, используя строку "read"
в качестве ключа".
Таблицы в Lua не являются на значениями, ни переменными; это объект. Если вы привычны к массивам в Java или Scheme, то прекрасно поймете, что мы имеем в виду. Однако, если ваши понятия о массивах сформированы в C или Pascal, вы должны немного напрячь мозг. Вы должны понимать таблицы как динамически определяемые объекты; ваша программа работает только со ссылками (указателями) на них. Никаких скрытых копий или создания новых таблиц "за сценой". Более того, вы не можете объявлять таблицы в Lua; на самом деле, нет даже возможности объявить их. Таблицы создаются посредством конструктора, простейшая форма которого выглядит как {}
:
a = {} -- создание таблицы и сохранение ссылки на нее в 'a' k = "x" a[k] = 10 -- новый элемент, с ключом "x" и значением 10 a[20] = "great" -- новый элемент, с ключом 20 и значением "great" print(a["x"]) --> 10 k = 20 print(a[k]) --> "great" a["x"] = a["x"] + 1 -- инкремент элемента "x" print(a["x"]) --> 11Тадлицы не имеют имен. Между значением, содержащимся в таблице и самой таблицей нет фиксированных взаимосвязей:
a = {} a["x"] = 10 b = a -- 'b' - ссылка на ту же таблицу, что и 'a' print(b["x"]) --> 10 b["x"] = 20 print(a["x"]) --> 20 a = nil -- теперь только 'b' хранит ссылку на таблицу b = nil -- а теперь ссылок на таблицу нет вовсеКогда в программе не остается действительных ссылок на таблицу, система управления памятью Lua удаляет таблицу и повторно использует выделенную ей память.
Каждая таблица может хранить данные с различным типом индексов увеличивается при необходимости добавления нового элемента:
a = {} -- пустая таблица -- создание 1000 новых элементов for i=1,1000 do a[i] = i*2 end print(a[9]) --> 18 a["x"] = 10 print(a["x"]) --> 10 print(a["y"]) --> nilОтносительно последней строки примера: Подобно глобальным перемнным, при отсутствии явной инициализации полю таблицы присваивается nil. Также аналогично глобальным переменным, для его удаления поля таблицы вы можете присвоить ему nil. Это не случайно: Lua хранит глобальные переменные в обычной таблице. Подробнее об этом можно узнать из Главы 14.
Для доступа к записям в качестве индекса используется имя поля. Lua поддерживает такое представление для обеспечения a.name
как синтаксического "сахара" для a["name"]
. Т.е., последнюю строку предыдущего примера можно было записать более аккуратно:
a.x = 10 -- то же, что и a["x"] = 10 print(a.x) -- то же, что и print(a["x"]) print(a.y) -- то же, что и print(a["y"])С точки зрения Lua, обе формы записи эквивалентны и могут свободно использоваться вперемешку; но для читающего код человека каждая форма может сигнализировать о различных намерениях (автора кода).
Обычная ошибка начинающих состоит в смешивании a.x
с a[x]
. Первая форма представляет a["x"]
, т.е. таблица индексируется по строке "x"
. Во втором случае таблица индексируется по значению переменной x
. Уловите разницу:
a = {} x = "y" a[x] = 10 -- запись 10 в поле "y" print(a[x]) --> 10 -- значение поля "y" print(a.x) --> nil -- хначение поля "x" (undefined) print(a.y) --> 10 -- значение поля "y"
Для представления обычных массивов, просто используйте таблицу с целочисленными ключами. Таким образом вы не указываете размер массива, а лишь инициализируете необходимые вам элементы:
-- чтение 10 строк и сохранение их в таблицу a = {} for i=1,10 do a[i] = io.read() endКогда вы перебираете элементы массива, первый не инициализированный элемент вернет nil; можно использовать это значение как признак конца массива. Например, вы хотите вывести строки, полученные в предыдущем примере, используя код:
-- вывод строк for i,line in ipairs(a) do print(line) endБазовая библиотека Lua содержит
ipairs
, удобную функцию, которая позволяет перебирать элементы массива, следуя соглашению о том, что концом массива является первый элемент, содержащий nil.
Так как таблицы могут индексироваться любым значением, вы можете начинать массивы с любого удобного вам числа. Однако, в Lua принято начинать массивы с 1 (а не с 0, как в C) стандартные библиотеки придерживаются этого соглашения.
Поскольку таблицы могут индексироваться любыми типами, при индексировании надо быть предельно внимательными и помнить, каков результат сравнения. Хотя можно индексировать таблицу и с помощью числа 0
, и с помощью строки "0"
, нужно помнить, что это два разных значения (согласно результату сравнения) и, соответственно, указывают они на разные позиции в таблице. Кроме того, строки "+1"
, "01"
и "1"
также указывают на разные позиции. Кгда вы сомневаетесь относительно текущего типа индексов, для полной уверенности используйте явное преобразование:
i = 10; j = "10"; k = "+10" a = {} a[i] = "one value" a[j] = "another value" a[k] = "yet another value" print(a[j]) --> another value print(a[k]) --> yet another value print(a[tonumber(j)]) --> one value print(a[tonumber(k)]) --> one valueВы можете внести труднонаходимую ошибку в вашу программу, если не будете уделять должного внимания этому вопросу.
Copyright © 2003-2004 Roberto Ierusalimschy. All rights reserved. | Перевод на русский Artem13 |
![]() |