Доступ к глубоко вложенной таблице без ошибок?

Для поля внутри глубоко вложенной таблицы, например text.title.1.font. Даже если вы используете

if text.title.1.font then ... end

это приведет к ошибке, такой как "попытка индексировать глобальный" текст "(нулевое значение)", если какой-либо уровень таблицы на самом деле не существует. Конечно, можно попытаться проверить существование каждого уровня таблицы, но это кажется довольно громоздким. Мне интересно, есть ли безопасный и более красивый способ справиться с этим, чтобы при обращении к такому объекту значение nil было бы вместо вызова ошибки?

2 ответа

Предложение Егора debug.setmetatable(nil, {__index = function()end}) это самый простой в применении. Имейте в виду, что он не имеет лексической области действия, поэтому, как только он будет включен, он будет "включен" до выключения, что может привести к непредвиденным последствиям в других частях вашего кода. Смотрите эту ветку для обсуждения и некоторых альтернатив.

Также обратите внимание, что text.title.1.font должно быть text.title[1].font или же text.title['1'].font (и эти два не то же самое).

Еще одна, более многословная, но все еще полезная альтернатива:

if (((text or {}).title or {})[1] or {}).font then ... end

Способ сделать это, который не вызывает много ошибок, состоит в том, чтобы явно указать Lua, какие поля каких таблиц должны быть таблицами по умолчанию. Вы можете сделать это с помощью метатаблиц. Ниже приведен пример, но он действительно должен быть настроен в соответствии с тем, как вы хотите, чтобы ваши таблицы были структурированы.

-- This metatable is intended to catch bugs by keeping default tables empty.
local default_mt = {
  __newindex =
    function()
      error(
    'This is a default table. You have to make nested tables the old-fashioned way.')
    end
}

local number_mt = {
  __index =
    function(self, key)
      if type(key) == 'number' then
    return setmetatable({}, default_mt)
      end
    end
}

local default_number_mt = {
  __index = number_mt.__index,
  __newindex = default_mt.__newindex
}

local title_mt = {__index = {title = setmetatable({}, default_number_mt)}}

local text = setmetatable({}, title_mt)

print(text.title[1].font)
Другие вопросы по тегам