如何在不出错的情况下访问深度嵌套的表?

对于一个深度嵌套表内的字段,例如text.title.1.font。即使您使用

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

如果表的任何一级实际上不存在,则会导致类似于“尝试对全局变量'text'进行索引(一个nil值)”的错误。当然,可能会尝试检查表的每个级别的存在,但这似乎相当麻烦。我想知道是否有一种安全和更漂亮的方法来处理这种情况,即在引用此类对象时,空值将是值,而不会触发错误?

点赞
用户1442917
用户1442917

Egor 建议 debug.setmetatable(nil, {__index = function()end}) 是最容易应用的方法。请注意,它没有词法作用域,所以一旦启用,它将一直处于“开”状态,这可能会对代码的其他部分产生意想不到的影响。请参见 this thread 以了解讨论和其他一些替代方法。

还要注意,text.title.1.font 应该改为 text.title[1].fonttext.title['1'].font(这两者并不相同)。

另一个更详细但仍可用的替代方法是:

if (((text or {}).title or {})[1] or {}).font then ... end
2014-05-21 16:30:29
用户3574628
用户3574628

为了避免引入许多错误,做到这一点的方法是明确地告诉 Lua 哪些表的哪些字段默认应该是表。可以使用元表来实现。以下是一个示例,但实际上应该根据您希望表的结构如何进行自定义。

-- 这个元表旨在通过保持默认表为空来捕捉错误。
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)
2014-05-21 17:59:45