我需要检查一个成员是否存在于不在下一级别的表中,而是存在于成员的路径中。
foo = {}
if foo.bar.joe then
print(foo.bar.joe)
end
这会投射attempt to index field 'bar' (a nil value)
,因为未定义条形码。
我通常的解决方案是逐个测试链条。
foo = {}
if foo.bar and foo.bar.joe then
print(foo.bar.joe)
end
但是当有许多嵌套表时,这可能非常繁琐。有没有更好的方法来进行这项测试而不是逐件?
答案 0 :(得分:2)
我不明白你所说的“沿着成员之路”是什么意思。从这个例子中,我假设你试图在“子表”中找到一个值?
local function search(master, target) --target is a string
for k,v in next, master do
if type(v)=="table" and v[target] then return true end
end
end
一个简单的例子。如果您使用此类函数,则可以传递foo
表和joe
字符串以查看是否存在foo.*.joe
。希望这会有所帮助。
答案 1 :(得分:2)
debug.setmetatable(nil, {__index = {}})
foo = {}
print(foo.bar.baz.quux)
print(({}).prd.krt.skrz.drn.zprv.zhlt.hrst.zrn) -- sorry ))
答案 2 :(得分:1)
如果我理解你的问题,这是一种可能性:
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的建议,这里有一个版本,也适用于当地人,但必须采取两个参数:(
function isField(t,s)
if t == nil then return false end
local t = t
for key in s:gmatch('[^.]+') do
if t[ key ] == nil then return false end
t = t[ key ]
end
return true
end
-- To test
local
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
答案 3 :(得分:1)
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创建临时变量。我的lua ver是5.1
在5.2 5.3中删除loadstring,而不是使用load
答案 4 :(得分:1)
要搜索表格任何级别的元素,我会使用这样的方法:
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
答案 5 :(得分:0)
我认为你正在寻找这些方面的东西:
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。似乎做了这个工作。尽管如此,请随意想出一个比“得到”更好的名字。
与往常一样,在与or
结合使用时要小心。
我对Egor的聪明回答印象深刻,但总的来说我认为我们不应该依赖这样的黑客攻击。
另见
Lua 5.2的“安全表导航”补丁:http://lua-users.org/wiki/LuaPowerPatches
关于此事的冗长讨论:http://lua-users.org/lists/lua-l/2010-08/threads.html#00519
我怀疑MetaLua已经实现了相关的内容,但目前我找不到。