Таблицы в Lua

Таблицы в языке Lua играют роль ассоциативного массива. В нём в качестве индексов выступают различные типы данных, кроме nil (ничто).

Свойства таблиц:

  • Т. — это объект;
  • Она может иметь неограниченный размер;
  • Т. – это пары ключ-значение. При этом и в ключе, и в значении может быть любой тип данных, кроме nil.

Разработчики Lua позиционируют таблицы как ведущий инструмент структурирования данных в своём языке.

Создаём таблицу в Луа

Пустая простая таблица

local t = {}

Чтоб получить доступ к её полю, используется такой синтаксис:

переменная[ключ]

Пример 1 с разными типами

t[1] = 10
t[«Пушкин»] = «поэт»
t[3] = true

local function f()
return 1
end

t[f] = «функция»
t[«функция»] = f
t.me = t — тоже самое, что t[«me»] = t — ссылка на самого себя
print(t[«функция»]()) — > 1

Идентификация таблицы при создании

local t = {1, 2, 3, x = 5, [«Пушкин»] = «поэт»}

Пример 2

t = {}
t[1] = «first» — новое поле с ключом 1 и значением «first»
t[2] = 20 – поле с ключом 2 и значением 20
k = «name»
t[k] = «Jane»
a = t[1] — присваиваем a значение «first»
b = t[2]
c = t[«name»]

Строковые ключи t[«name»] записать проще — t.name:

t.name = «name» — равнозначно t[«name»] = «name»
a = t.name — равнозначно a = t[«name»]

Важно! В 1 случае представлено поле таблицы с ключом «name» (оно равнозначно t[«name»]). Второе выражение — это поле, где ключ есть идентификатор переменной name. Рассмотрим различие более подробно:

t = {}name = «somebody» t[name] = «Jane» — в поле «somebody» помещено значение «Jane»a = t[name] — переменная a получает значение поля «somebody» («Jane»)b = t.name — переменная b получает nilc = t.somebody — переменная c получает значение поля «somebody» («Jane»)

Если поля с заданным ключом нет, обращение к нему возвращает nil:

t = {}
a = t.name — переменная a получает значение nil

Как следствие, можно удалить поле, присвоив ему пустое nil:

t.second = nil

Заполнение таблицы при создании. В {} помещаем ключи и значения по примеру из начала статьи. Элементы следует разделять запятыми или точками с запятой:

t = {[«apple»]=»яблоко», [«orange»]=»апельсин», [«lemon»]=»лимон»}

Это равнозначно коду ниже:

t = {}
t.apple = «яблоко»; t.orange = «апельсин»; t.lemon = «лимон»

При работе со строковыми ключами квадратные скобки (и двойные кавычки) можно опустить:

t = {apple=»яблоко», orange=»апельсин», lemon=»лимон»}

Можно создать таблицу, где поля тоже являются таблицами:

points = {
a = {x=20, y=1},
b = {x=40, y=2}
}

Или:

points = {}
p.a = {x=20, y=1},
p.b = {x=40, y=2}

Массивы

Если при инициализации таблицы ключи не были указаны, то язык сам присваивает значения ключей, начиная с 1.

Важно! Адресация массивов начинается не с 0, а 1.

local t = {3, 4, 5}
print(t[1], t[2], t[3]) — > 3, 4, 5

Чтобы не нарушать структуру при работе с элементами массива, надо использовать библиотеку Lua table.

local t = {1, 2, 3, 4, 5}

  1. table.insert(t, 6) — добавляет элемент в конец массива. Теперь t = {1, 2, 3, 4, 5, 6}
  2. table.insert(t, 0, 1) — вставляет элемент по индексу, сдвигая оставшиеся элементы массива. Теперь t = {0, 1, 2, 3, 4, 5, 6}
  3. table.remove(t, 3) — удаляет из таблицы элемент по индексу 3 и сдвигает оставшиеся элементы. Теперь t = {0, 1, 3, 4, 5, 6}

Чтобы посчитать размер массива, используйте #:

local count = #t

Оператор # возвращает max индекс непрерывной последовательности ключей от начала массива.

local t = {1, [100] = 2}
print(#t) — > 1, поскольку t[1] не nil, а t[1 + 1] равно nil.

У массива, в котором значения хранятся одно за другим, # вернёт количество его элементов.

Обход элементов таблицы

Выяснить, сколько элементов содержится в таблице Lua можно только с помощью их обхода. Исключение — это массивы и оператор # для определения длины массива. Обходим массив с помощью цикла for:

local t = {1, 2, 3, «Ваня»}
for i = 1, #t, 1 do
print(t[i])
end

— > 1
— > 2
— > 3
— > Ваня

Обычные таблицы обходятся циклом for:

local t = {1, 2, x = 4, y = 5, [«Пушкин»] = «поэт»}
for key, value in pairs(t) do
print(key, value)
end

— > 1 1
— > 2 2
— > y 5
— > x 4
— > Пушкин поэт

Порядок элементов в таблице отличается от порядка, в котором значения помещали в таблицу.

Методы

Попытка смоделировать объектно-ориентированное программирование:

local t = {x = 1}

function t:fun()
print(self.x)
end

t:fun()

— > 1

Что означает этот код?

  1. Создание таблицы t;
  2. В ней ввели поле x и присвоили ему значение 1;
  3. В таблице создали функцию fun;
  4. Внутри неё обратились к таблице через переменную self (где self это первый скрытый параметр у функции. Вызов функции как t:fun() аналогичен вызову t.fun(t))
  5. Вызвали в таблице t метод fun;

Мы создали объект, его метод и вызов. При этом нет возможности создавать объекты с определённым типом. Объект и метод существуют в одном виде. Для того, чтобы создать объект типа tt, который действует так же, как объект типа t, нам следует повторить код с самого начала

Есть ли решение? Да. Но для этого надо изучить метатаблицы.

local tt = {x = 2}

function tt:fun()
print(self.x)
end

function checkMetod(x)
x:fun()
end

checkMetod(t)
checkMetod(tt)

—> 1
—> 2

Метатаблицы

Мета таблицы переопределяют действие встроенных типов. Они подобны конструкции operator() в Cpp. Рассмотрим, как можно сложить две таблицы (в Lua данная возможность не встроена).

local data1 = {x = 1}

local data2 = {x = 2}
— создаем таблицу
local meta = {}
— в таблице определяем специальное поле __add (оператор +)
function meta.__add(op1, op2)
return op1.x + op2.x
end

setmetatable(data1, meta)

print(data1 + data2) —> 3

Создаём два объекта, в каждом присутствует поле х. Затем создаём таблицу meta. В ней определяем функцию с именем __add. В завершении установили метатаблицу первому операнду.

Заключение

Таблица – это фундаментальная основа Lua, воплощающая практически все его возможности.
Так как функции относятся к значениям первого класса, поля таблицы могут содержать и функции. Таким образом, таблицы хранят и методы.

Реализация ассоциативных массивов в Lua крайне эффективна. Скорость вычисления хэш-функций в Lua практически безупречна. Интерпретируемые Lua скрипты справляются с этой задачей в 2 раза медленнее программ на языке C. А вычисление функций значительно быстрее, чем аналоги на Perl, Ruby и Python.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *