Вы можете решить эту проблему, используя прокси-метатабельный и сомнительный шаблон Null Object.
Нулевой объект может выглядеть так:
local Null = {}
local NullProto = { __index = function(t,k) return Null end }
setmetatable(Null, NullProto)
Null
всегда будет возвращаться при попытке индексирования.
Ключевой идеей решения является создание прокси-объекта для исходной таблицы, который будет использовать следующую логику:
- Если какой-либо ключ не существует в исходной таблице, вернуть Null Object
- Если какой-то ключ существует в исходной таблице
- Если ссылочное значение имеет примитивный тип, вернуть значение
- Если указанное значение относится к табличному типу, обернуть его прокси и вернуть
Код может выглядеть следующим образом
function make_safe_table(nonsafe)
local proto = {
__index = function(t, k)
local val = nonsafe[k]
if val == nil then
return Null
elseif type(val) == 'table' then
return make_safe_table(val)
else
return val
end
end
}
return setmetatable({}, proto)
end
Вы можете использовать эту функцию следующим образом:
local original = {
nested = {
deep = { hidden = 'value'}
},
simple = 'simple',
[3] = 'third'
}
local safe_original = make_safe_table(original)
print(safe_original.not_exists == Null) -- true
print(safe_original.nested.not_exists == Null) -- true
print(safe_original.nested.deep.not_exists == Null) -- true
print(safe_original.not_exists.still_not_exists == Null) -- true
print(safe_original.nested.deep.hidden) -- 'value'
print(safe_original.simple) -- 'simple'
print(safe_original[3]) -- 'third'
Я бы не рекомендовал вам использовать этот код в производственной среде, поскольку он не был должным образом протестирован, но я надеюсь, что он поможет вам создать надежное решение.
См. https://www.lua.org/pil/13.4.html для более подробной информации о метатаблицах.