В Lua таблицы - "собирательный" тип данных, представляющие из себя ассоциативные массивы, то есть они сохраняют данные по типу "ключ-значение"
Создание таблицы
Таблицы создаются при помощи двойных фигурных скобок { } .
Создадим пустую таблицу:
Создадим пустую таблицу:
> t = {} -- создаём пустую таблицу, присваиваем её переменной t
> print(t)
table: 0035AE18
Обратите внимание, когда мы попытались отобразить таблицу, напечатались только её тип и уникальный id.
Чтобы отобразить данные таблицы, нужно использовать другой метод, но о нём позже.
Чтобы отобразить данные таблицы, нужно использовать другой метод, но о нём позже.
Использование таблиц
Чтобы получить доступ к данным в таблице по ключу, мы используем следующую конструкцию: table [key]
> t = {}
> t["foo"] = 123 -- устанавливаем значение 123 по ключу "foo" в таблице
> t[3] = "bar" --устанавливаем значение "bar" по ключу 3 в таблице
> = t["foo"]
123
> = t[3]
bar
Если по данному ключу нету значения, возвращается nil
> t = {}
> = t["foo"]
nil
Можно удалить пару "ключ-значение", установив значение nil по ключу.
Любое значение может быть использовано как ключ, кроме nil и NaN (несуществующее число)
Любое значение может быть использовано как ключ, кроме nil и NaN (несуществующее число)
> t = {}
> k = {}
> f = function () end
> t[k] = 123
> t[f] = 456
> = t[k]
123
> = t[f]
456
> t[nil] = 123
stdin:1: table index is nil
stack traceback:
stdin:1: in main chunk
[C]: in ?
> t[0/0] = 123
stdin:1: table index is NaN
stack traceback:
stdin:1: in main chunk
[C]: in ?
Довольно часто строки используют как ключ: для них есть специальные сокращения:
> t = {}
> t.foo = 123 --тоже, что и t["foo"] (не путайте с t[foo], что использует переменную foo как ключ)
> = t.foo
123
> = t["foo"]
123
Такие сокращения доступны для строк, содержащие знаки подчёркивания, буквы, числа (но не начинающиеся с чисел!)
Можно добавлять данные сразу при создании таблицы:
> t = {["foo"] = "bar", [123] = 456}
> = t.foo
bar
> = t[123]
456
Тут точно также можно использовать сокращения:
> t = {foo = "bar"} -- same as ["foo"]="bar" (but not [foo]="bar" , that would use the variable foo)
> = t["foo"]
bar
Для перебора всех данных в таблице, используется итератор pairs
> t = {foo = "bar", [123] = 456}
> for key,value in pairs(t) do print(key,value) end
foo bar
123 456
Порядок в котором перебирается таблица не определён. Пусть вы и добавляли в таблицу данные в определённой последовательности, цикл может перебирать их в другом порядке.
Таблицы как массивы
В действительности в Lua нет массивов, однако можно использовать таблицы как массивы.
Для этого при создании таблицы, надо разделять список данных запятыми:
Для этого при создании таблицы, надо разделять список данных запятыми:
> t = {"a", "b", "c"}
> = t[1]
a
> = t[3]
c
Можно и так:
> t = {[1]="a", [2]="b", [3]="c"}
> = t[1]
a
> = t[3]
c
Можно совмещать синтаксис обычных таблиц и массивов:
> t = {"a", "b", [123]="foo", "c", name="bar", "d", "e"}
> for k,v in pairs(t) do print(k,v) end
1 a
2 b
3 c
4 d
5 e
123 foo
name bar
Индексация начинается с 1 (в отличии от многих других языков, где индексация начинается с 0).
Можно получить длину массива, используя оператор #
> t = {"a", "b", "c"}
> = #t
3
Оператор # не считает элементы в массиве, а просто возвращает номер последнего ключа. Естественно, он выдаст неверный результат, если члены массива не последовательны.
Два способа, как добавить значение в конец массива:
> t = {}
> table.insert(t, 123)
> t[#t+1] = 456
> = t[1]
123
> = t[2]
456
используя table.insert, можно вставлять значения в середину массивов, в этом случае он сдвигает индексы остальных значений:
> t = {"a", "c"}
> table.insert(t, 2, "b")
> = t[1], t[2], t[3]
a b c
table.remove удаляет объект из массива, также сдвигая индексы:
> t = {"a", "b", "c"}
> table.remove(t, 2)
> = t[1], t[2]
a c
Для перебора массивов используется итератор ipairs. В отличии от pairs, перебирает массивы по порядку:
> t = {"a", "b", "c"}
> for i, v in ipairs(t) do print(i, v) end
1 a
2 b
3 c
Для соединения строк в массиве используется функция table.concat. Функция принимает параметры separator (разделитель), start (начало) и end (конец).
Пример с разделителем:
Пример с разделителем:
> t = {"a", "b", "c"}
> = table.concat(t, ";")
a;b;c
Табличные значения - ссылочные.
Когда мы назначаем таблицу переменной, мы не создаём новую таблицу, мы получаем ссылку на неё:
Когда мы назначаем таблицу переменной, мы не создаём новую таблицу, мы получаем ссылку на неё:
> t = {}
> u = t
> u.foo = "bar"
> = t.foo
bar
> function f(x) x[1] = 2 end
> f(t)
> = u[1]
2
Таблицы удаляются из памяти "сборщиком мусора", когда исчезает последняя ссылка на неё.
Также следует помнить, что при сравнении таблиц используются ссылки на таблицы:
> table1 = {}
> table2 = {}
> table3 = table1
> = table1 == table2 -- разные таблицы
false
> = table1 == table3 -- ссылаются на одну таблицу
true
В Lua нет стандартных функций для копирования таблиц, так что это придётся делать ручками.
Таблицы как неупорядоченные списки
Часто новички в Lua создают массивы для хранения разных объектов. Проблема в том, что удаление объектов из такого массива и проверка находится ли объект в массиве - медлительны (приходится постоянно перебирать массив)
Проблему можно решить так: добавляем объект в ключ и устанавливаем ему значение-пустышку (например true). Таким образом можно использовать неупорядоченные списки с быстрым доступом к объектам, добавлением и удалением.
Отличия от обычных массивов в том, что нельзя будет добавить один и тот же объект дважды, и для получения кол-ва объектов всё же придётся перебирать список.
local items = {}
-- добавляем объект в список
items["foo"] = true
items[123] = true
--проверяем есть ли значение "foo"в списке
if items["foo"] then
-- тут может быть ваш код
end
-- удаление объекта из списка
items[123] = nil
данная статья является вольным переводом с сайта lua-users.org
с возможными дополнениями и изменениями
с возможными дополнениями и изменениями