2.5 - Таблицы

Тадлицы реализуются массивами соответствий (ассоциативными массивами). Ассоциативный массив - это массив, который может индексироваться не только числом, но также и строкой или любым другим значением языка, исключая 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
Вы можете внести труднонаходимую ошибку в вашу программу, если не будете уделять должного внимания этому вопросу.
Hosted by uCoz