|
Программирование на 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 |
|