【问题标题】:Accessing deeply nested table without error?访问深度嵌套的表没有错误?
【发布时间】:2014-07-09 20:34:38
【问题描述】:

对于深度嵌套表中的字段,例如 text.title.1.font。即使你使用

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

如果表的任何级别实际上不存在,则会导致诸如“尝试索引全局'文本'(一个零值)”之类的错误。当然,可能会尝试检查表的每一级是否存在,但这似乎相当麻烦。我想知道是否有一种更安全、更漂亮的方法来处理这个问题,这样在引用这样的对象时,nil 将是值而不是触发错误?

【问题讨论】:

  • debug.setmetatable(nil, {__index = function()end})
  • Autotables/Autovivification(参见12)在大多数情况下也能很好地工作,同时不需要修改nil 元表,也不需要调试库。顺便说一句,1.: 语法无效。以这种方式索引的索引必须以字母 (a-Z) 或下划线开头。 (3)

标签: debugging lua lua-table meta-method


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这样做不会引起很多错误的方法是明确告诉 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-24
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      • 2021-01-03
      • 2021-05-28
      • 1970-01-01
      相关资源
      最近更新 更多