检查Lua表成员是否存在于任何级别
我需要检查一个成员是否存在于一个表中,该表不在下一级,而是沿着一条成员路径检查Lua表成员是否存在于任何级别,lua,lua-table,Lua,Lua Table,我需要检查一个成员是否存在于一个表中,该表不在下一级,而是沿着一条成员路径 foo = {} if foo.bar.joe then print(foo.bar.joe) end 这将抛出一个尝试索引字段“bar”(一个nil值),因为bar没有定义 我通常的解决办法是一件一件地测试链条 foo = {} if foo.bar and foo.bar.joe then print(foo.bar.joe) end 但是,当有许多嵌套表时,这可能非常乏味。有没有比逐件测试更好的方法?我
foo = {}
if foo.bar.joe then
print(foo.bar.joe)
end
这将抛出一个尝试索引字段“bar”(一个nil值)
,因为bar没有定义
我通常的解决办法是一件一件地测试链条
foo = {}
if foo.bar and foo.bar.joe then
print(foo.bar.joe)
end
但是,当有许多嵌套表时,这可能非常乏味。有没有比逐件测试更好的方法?我不明白你所说的“沿着成员的路径”是什么意思。从这个例子中,我假设您试图在“子表”中找到一个值
一个简单的例子。如果使用这样的函数,可以传递
foo
表和joe
字符串以查看foo.*.joe
是否存在。希望这能有所帮助。我想您正在寻找以下线索:
debug.setmetatable(nil, {__index = {}})
foo = {}
print(foo.bar.baz.quux)
print(({}).prd.krt.skrz.drn.zprv.zhlt.hrst.zrn) -- sorry ))
local function get(Obj, Field, ...)
if Obj == nil or Field == nil then
return Obj
else
return get(Obj[Field], ...)
end
end
local foo = {x = {y = 7}}
assert(get() == nil)
assert(get(foo) == foo)
assert(get(foo, "x") == foo.x)
assert(get(foo, "x", "y") == 7)
assert(get(foo, "x", "z") == nil)
assert(get(foo, "bar", "joe") == nil)
assert(get(foo, "x", "y") or 41 == 7)
assert(get(foo, "bar", "joe") or 41 == 41)
local Path = {foo, "x", "y"}
assert(get(table.unpack(Path)) == 7)
get
只需遍历给定路径,直到遇到nil。似乎能胜任这项工作。尽管如此,你还是可以想出一个比“得到”更好的名字
与往常一样,与或组合时要小心
伊戈尔的聪明回答给我留下了深刻的印象,但总的来说,我认为我们不应该依赖这些黑客
另请参见
- Lua 5.2的“安全表导航”修补程序:
- 关于这个问题的冗长讨论:
- 相关技术:
- 我怀疑MetaLua中已经实现了一些相关的功能,但目前我找不到
如果我正确理解了您的问题,这里有一种可能性:
function isField(s)
local t
for key in s:gmatch('[^.]+') do
if t == nil then
if _ENV[ key ] == nil then return false end
t = _ENV[ key ]
else
if t[ key ] == nil then return false end
t = t[ key ]
end
--print(key) --for DEBUGGING
end
return true
end
-- To test
t = {}
t.a = {}
t.a.b = {}
t.a.b.c = 'Found me'
if isField('t.a.b.c') then print(t.a.b.c) else print 'NOT FOUND' end
if isField('t.a.b.c.d') then print(t.a.b.c.d) else print 'NOT FOUND' end
更新:根据cauterite的建议,这里有一个版本也适用于本地人,但必须有两个论点:(
foo={}
foo.boo={}
foo.boo.jeo={}
foo.boo.joe是foo['boo']['joe']等等
我做下一个函数
function exist(t)
local words = {}
local command
for i,v in string.gmatch(t, '%w+') do words[#words+1] = i end
command = string.format('a = %s', words[1])
loadstring(command)()
if a == nil then return false end
for count=2, #words do
a = a[words[count]]
if a == nil then return false end
end
a = nil
return true
end
foo = {}
foo.boo = {}
foo.boo.joe = {}
print(exist('foo.boo.joe.b.a'))
使用loadstring生成temp变量。我的lua ver是5.1
删除5.2 5.3中的loadstring,而不是使用load来搜索表中任何级别的元素,我将使用如下方法:
function exists(tab, element)
local v
for _, v in pairs(tab) do
if v == element then
return true
elseif type(v) == "table" then
return exists(v, element)
end
end
return false
end
testTable = {{"Carrot", {"Mushroom", "Lettuce"}, "Mayonnaise"}, "Cinnamon"}
print(exists(testTable, "Mushroom")) -- true
print(exists(testTable, "Apple")) -- false
print(exists(testTable, "Cinnamon")) -- true
foo.bar.joe
相当于\u G['foo'].bar.joe
(如果作用域中没有局部变量foo
)而不是\u G['foo.bar.joe']
!您无法使用普通变量语法访问后者,因为它包含对变量名无效的字符。现在它引发了一个错误(与问题中一样,出于同样的原因)。我建议将其实现为isField(t,s)
-尝试从字符串中的第一个组件获取表只适用于全局。例如,local u={v=1};assert(isField('u.v'))
失败。相应地进行了更新。谢谢。我很惊讶这个简单而优雅的答案没有得到任何支持。
function exist(t)
local words = {}
local command
for i,v in string.gmatch(t, '%w+') do words[#words+1] = i end
command = string.format('a = %s', words[1])
loadstring(command)()
if a == nil then return false end
for count=2, #words do
a = a[words[count]]
if a == nil then return false end
end
a = nil
return true
end
foo = {}
foo.boo = {}
foo.boo.joe = {}
print(exist('foo.boo.joe.b.a'))
function exists(tab, element)
local v
for _, v in pairs(tab) do
if v == element then
return true
elseif type(v) == "table" then
return exists(v, element)
end
end
return false
end
testTable = {{"Carrot", {"Mushroom", "Lettuce"}, "Mayonnaise"}, "Cinnamon"}
print(exists(testTable, "Mushroom")) -- true
print(exists(testTable, "Apple")) -- false
print(exists(testTable, "Cinnamon")) -- true