Вложенные таблицы

Строим сложные структуры данных, вкладывая таблицы друг в друга.

Вложенная таблица — это таблица, которая хранится как значение внутри другой таблицы, образуя дерево данных.

Реальные данные сложнее плоского списка. Команда героев, инвентарь, уровень игры — всё это таблицы внутри таблиц. Lua позволяет вкладывать их сколько угодно глубоко.

Таблица внутри таблицы

local game = {
  title = "Подземелье",
  player = {
    name = "Алиса",
    inventory = {"меч", "щит", "зелье"}
  }
}
print(game.player.name)
print(game.player.inventory[1])

Вывод:

Алиса
меч

Доступ идёт по цепочке: gameplayername. Каждая точка спускает нас на уровень глубже.

Список объектов

Очень частый приём — список таблиц-объектов, например список врагов:

local enemies = {
  {name = "гоблин", hp = 30},
  {name = "орк", hp = 50},
  {name = "дракон", hp = 200}
}
for i, e in ipairs(enemies) do
  print(e.name .. ": " .. e.hp .. " hp")
end

Вывод:

гоблин: 30 hp
орк: 50 hp
дракон: 200 hp

Схема вложенности

game
 ├─ title = "Подземелье"
 └─ player
     ├─ name = "Алиса"
     └─ inventory
         ├─ [1] = "меч"
         ├─ [2] = "щит"
         └─ [3] = "зелье"

Изменение вложенных данных

enemies[1].hp = enemies[1].hp - 10   -- гоблин получил урон
table.insert(game.player.inventory, "факел")
print(enemies[1].hp, #game.player.inventory)

Вывод:

20	4

Как работает под капотом

Таблицы в Lua — это ссылочный тип. Когда вы пишете game.player, в переменной хранится не копия таблицы, а ссылка на неё. Поэтому изменение через enemies[1].hp меняет оригинал, а если присвоить таблицу другой переменной, обе будут указывать на одни данные.

Частые ошибки

  • Копировать таблицу простым присваиванием b = a. Это копирует ссылку, а не данные — изменения видны через обе переменные.
  • Обращаться к полю несуществующей вложенной таблицы: game.boss.hp упадёт с ошибкой, если boss равен nil.
  • Забывать, что глубина вложенности ничем не ограничена, и легко запутаться в длинных цепочках.

Итог

  • Таблицы можно вкладывать друг в друга, создавая деревья данных любой глубины.
  • Доступ к вложенным значениям — цепочка из точек и скобок: a.b.c[1].
  • Список таблиц-объектов — типичный способ описать врагов, предметы, игроков.
  • Таблицы передаются по ссылке: присваивание копирует ссылку, а не сами данные.
Проверьте себя
1. Что произойдёт при b = a, где a — таблица, а потом изменении b?
Ab — независимая копия, a не меняется
Bb и a ссылаются на одну таблицу, изменения видны в обеих
CВозникнет ошибка
Da станет nil
2. Как обратиться к имени первого врага в списке enemies = {{name="гоблин"}}?
Aenemies.name
Benemies[1].name
Cenemies.1.name
Denemies->name