Lua Academy · Урок

Вложенные таблицы и структурированные данные

Создавайте вложенные структуры и обращайтесь к полям на разных уровнях вложенности.

Урок 4 из 412 шагов

«Вложенные таблицы и структурированные данные» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Основы вложенных таблиц

Таблицы могут содержать другие таблицы в качестве значений, создавая структуры произвольной глубины. Обращайтесь к вложенным полям, последовательно используя точки или скобки. Отсутствующие промежуточные таблицы вызывают ошибки — всегда проверяйте, что родительские таблицы существуют, прежде чем обращаться к глубоким полям.

local company = {
  name = "CoddyKit",
  address = {
    city = "Istanbul",
    country = "Turkey",
    zip = "34000"
  },
  employees = 25
}

print(company.name)            -- CoddyKit
print(company.address.city)    -- Istanbul
print(company["address"]["zip"]) -- 34000

Безопасный доступ к вложенным полям

Обращение к полю значения nil приводит к сбою с ошибкой «attempt to index a nil value». Защититесь от этого с помощью короткого замыкания оператора and: t and t.a and t.a.b. В некоторых проектах определяют вспомогательную функцию get(t, ...), которая безопасно проходит по цепочке ключей.

local function get(t, ...)
  local cur = t
  for _, key in ipairs({...}) do
    if type(cur) ~= "table" then return nil end
    cur = cur[key]
  end
  return cur
end

local data = {user = {profile = {age = 30}}}
print(get(data, "user", "profile", "age"))    -- 30
print(get(data, "user", "missing", "field"))  -- nil

Массив записей

Распространённый шаблон — массив таблиц (записей). Каждый элемент представляет собой таблицу с именованными полями. Выполняйте перебор с помощью ipairs и обращайтесь к полям по имени. Это аналог массива объектов или списка структур в Lua.

local users = {
  {id=1, name="Alice", score=95},
  {id=2, name="Bob",   score=87},
  {id=3, name="Carol", score=91},
}

for _, user in ipairs(users) do
  print(user.id, user.name, user.score)
end

Динамическое построение вложенных таблиц

Создавайте вложенные структуры поэтапно, формируя внутренние таблицы по мере необходимости. Всегда инициализируйте таблицу перед добавлением в неё элементов. Распространённая ошибка — забыть создать внутреннюю таблицу, а затем попытаться обратиться к nil по индексу.

local tree = {}
tree.root = {value = 10}
tree.root.left = {value = 5}
tree.root.right = {value = 15}
tree.root.left.left = {value = 2}

print(tree.root.value)            -- 10
print(tree.root.left.value)       -- 5
print(tree.root.left.left.value)  -- 2

Таблица как конфигурация в стиле JSON

Таблицы Lua часто используют для конфигурационных файлов, подобно JSON или YAML. Файл возвращает таблицу, а приложение загружает её с помощью dofile() или require(). Вложенные таблицы представляют вложенные разделы конфигурации.

-- config.lua (returned table)
local config = {
  server = {
    host = "0.0.0.0",
    port = 8080,
    ssl  = false,
  },
  db = {
    host = "localhost",
    name = "appdb",
    pool_size = 10,
  },
  logging = { level = "info", file = "/var/log/app.log" }
}

print(config.server.port)      -- 8080
print(config.db.pool_size)    -- 10

Граф в виде списка смежности

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

local graph = {
  A = {"B", "C"},
  B = {"A", "D"},
  C = {"A", "D"},
  D = {"B", "C"},
}

-- BFS from A
local visited = {A=true}
local queue = {"A"}
while #queue > 0 do
  local node = table.remove(queue, 1)
  io.write(node .. " ")
  for _, neighbor in ipairs(graph[node]) do
    if not visited[neighbor] then
      visited[neighbor] = true
      queue[#queue+1] = neighbor
    end
  end
end
print()  -- A B C D

Изменение вложенных полей

Изменяйте вложенные поля, обращаясь к родительской таблице и присваивая значение ключу. Поскольку таблицы передаются по ссылке, любая функция, получившая таблицу, может изменить её содержимое на месте — вызывающая сторона увидит эти изменения.

local player = {name="Hero", stats={hp=100, mp=50, atk=20}}

local function takeDamage(p, dmg)
  p.stats.hp = math.max(0, p.stats.hp - dmg)
end

takeDamage(player, 35)
print(player.stats.hp)   -- 65

player.stats.atk = player.stats.atk + 5
print(player.stats.atk)  -- 25

Сериализация вложенных таблиц

Преобразование вложенной таблицы в строку полезно для отладки или журналирования. Простой рекурсивный сериализатор обрабатывает вложенность любой глубины, но не умеет работать с циклами (циклическими ссылками).

local function serialize(val, indent)
  indent = indent or 0
  local pad = string.rep("  ", indent)
  if type(val) ~= "table" then
    return tostring(val)
  end
  local parts = {"{"}
  for k, v in pairs(val) do
    parts[#parts+1] = pad.."  "..tostring(k).."="..serialize(v,indent+1)
  end
  parts[#parts+1] = pad.."}"
  return table.concat(parts, "\n")
end
local data = {x=1, nested={y=2, z=3}}
print(serialize(data))

Разреженные матрицы

Наивное хранение двумерной матрицы приводит к перерасходу памяти для больших разреженных входных данных. Храните только ненулевые элементы во вложенной таблице: matrix[row][col] = value. Так можно эффективно представлять огромные матрицы, если большинство значений равно нулю.

local function newMatrix()
  return setmetatable({}, {__index=function(t,k)
    local row = {}
    rawset(t, k, row)
    return row
  end})
end

local m = newMatrix()
m[1][1] = 5
m[3][7] = 12
m[100][200] = 99

print(m[1][1])    -- 5
print(m[3][7])    -- 12
print(m[2][5])    -- nil (sparse: no value)

Проверка глубокой эквивалентности

Таблицы сравниваются по ссылке с помощью ==, а не по значению. Чтобы структурно сравнить вложенные таблицы, напишите рекурсивную функцию сравнения, которая сопоставляет каждую пару «ключ–значение» и рекурсивно обрабатывает вложенные таблицы.

local function deepEqual(a, b)
  if type(a) ~= type(b) then return false end
  if type(a) ~= "table" then return a == b end
  for k, v in pairs(a) do
    if not deepEqual(v, b[k]) then return false end
  end
  for k in pairs(b) do
    if a[k] == nil then return false end
  end
  return true
end
print(deepEqual({1,{2,3}},{1,{2,3}}))  -- true
print(deepEqual({1,{2,3}},{1,{2,4}}))  -- false

Быстрая проверка

Что происходит при обращении к t.a.b, если t.a равно nil?

Итоги: вложенные таблицы

Краткое содержание:

  • Таблицы можно вкладывать на любую глубину: t.a.b.c
  • Защищайте глубокий доступ: t and t.a and t.a.b
  • Таблицы — ссылочные типы, поэтому функции изменяют их на месте
  • Массив записей: {{name=...},{name=...}}
  • Разреженная матрица: вложенные таблицы для экономии памяти
  • Для глубокой эквивалентности требуется рекурсивное сравнение
Можно начать бесплатно

Изучай Lua с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
40
Уроки
159

Часто задаваемые вопросы

Урок «Вложенные таблицы и структурированные данные» бесплатный?

Да — полный текст урока «Вложенные таблицы и структурированные данные» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Вложенные таблицы и структурированные данные»?

Создавайте вложенные структуры и обращайтесь к полям на разных уровнях вложенности. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Вложенные таблицы и структурированные данные»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Таблицы как массивы
  2. Таблицы как словари
  3. Перебор таблиц с pairs и ipairs
  4. Вложенные таблицы и структурированные данные
← Назад к Lua Academy