Доступ к глубоко вложенной таблице без ошибок?
Для поля внутри глубоко вложенной таблицы, например 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)