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



我正在尝试使用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行LoPwS_row中的Lua错误:尝试索引字段"P1629"(零值(。

如果我执行:

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

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

如果存在字段,是否有简单的测试解决方案?谢谢

如果表链中有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

您可以使用代理元表和可疑的Null对象模式来解决这个问题。空对象可能如下所示:

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有关跖骨的更多详细信息。

相关内容

  • 没有找到相关文章

最新更新