如何检查Lua中是否存在表子字段?

时间:2018-11-03 01:36:33

标签: lua wikidata wikidata-api

我正在尝试使用Wikidata的Lua模型。

我需要在Wikidata的实体中搜索特定的ID:

    subjectitemofthisproperty = 'Q' .. tostring( entity['claims']['P1629'][1]["mainsnak"]["datavalue"]["value"]["numeric-id"] )

主要问题是某些实体没有entity['claims']['P1629'][1]["mainsnak"]["datavalue"]["value"]["numeric-id"]子字段。

Lua返回:

  

第80行的Module:LoPwS_row中的Lua错误:尝试索引字段   “ P1629”(无值)。

如果我做一个:

if entity['claims']['P1629'][1]["mainsnak"]["datavalue"]["value"]["numeric-id"] ~= nil then

因为条件调用该字段,然后返回相同的错误,所以它将不起作用。

是否有简单的解决方案来测试字段是否存在?谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用可代理代理且有问题的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

答案 1 :(得分:1)

您可以编写一个简单的函数,如果表链中某处有nil,则该函数将返回nil。我们称之为lookup

function lookup(t, ...)
    for _, k in ipairs{...} do
        t = t[k]
        if not t then
            return nil
        end
    end
    return t
end

-- Test it
t = {a = {b = {c = 5}}}
lookup(t, 'a', 'x', 'b') -- Returns nil
lookup(t, 'a', 'b', 'c') -- Returns 5