Lua:尝试索引 nil 值;避免条件语句中的错误

问题描述 投票:0回答:4

假设我有一张巨大的桌子,例如:

test.test[1].testing.test.test_test

不保证该表存在。包含它的表也不是。我希望能够做到:

if test.test[1].testing.test.test_test then
   print("it exits!")
end

但是,当然,如果尚未定义任何索引,这会给我一个“尝试索引?(零值)”错误。很多次,我最终都会做这样的事情:

if test then
   if test.test then
      if test.test[1] then
         if test.test[1].testing then -- and so on

有没有更好、更省事的方法来实现这一点?

if-statement lua
4个回答
3
投票

您可以编写一个函数,该函数需要查找键列表,并在找到该条目时执行您想要的任何操作。这是一个例子:

function forindices(f, table, indices)
  local entry = table

  for _,idx in ipairs(indices) do
    if type(entry) == 'table' and entry[idx] then
      entry = entry[idx]
    else
      entry = nil
      break
    end
  end

  if entry then
    f()
  end
end

test = {test = {{testing = {test = {test_test = 5}}}}}

-- prints "it exists"
forindices(function () print("it exists") end,
           test,
           {"test", 1, "testing", "test", "test_test"})

-- doesn't print
forindices(function () print("it exists") end,
           test,
           {"test", 1, "nope", "test", "test_test"})

顺便说一句,解决此类问题的函数式编程概念是“Maybe monad”。你也许可以用 Lua 的 monad 实现 来解决这个问题,尽管这不是很好,因为没有语法糖。


3
投票

debug.setmetatable(nil, { __index=function () end }) print(test.test[1].testing.test.test_test) test = {test = {{testing = {test = {test_test = 5}}}}} print(test.test[1].testing.test.test_test)

您也可以使用空表:

debug.setmetatable(nil, { __index={} })



0
投票

if test and test.test and test.test[1] and test.test[1].testing and test.test[1].testing.test and test.test[1].testing.test.test_test then print("it exits!") end

但是,当然,我会尝试重构它,以便不需要那么多嵌套。


0
投票

if (((((test or {}).test or {})[1] or {}).testing or {}).test or {}).test_test then print"it exists!" end

只需将每个 
t[k]

t.k
替换为
(t or {})[k]
(t or {}).k
,这将导致
nil
被替换为
{}
,以便后续索引操作成功(但可能再次产生
nil
)。
警告:这很可能会创建不必要的垃圾表;你的 Lua 实现不太可能“优化它们”。它也比自己写一个助手方便。我通常编写的帮助程序使用可变参数来避免创建临时表:

function nilget(t, ...) for i = 1, select("#", ...) do if t == nil then return nil end t = t[select(i, ...)] end return t end

用法:
nilget(test, "test", 1, "testing", "test", "test_test")

我建议

更改nil的调试元表;这有效地将所有索引操作放宽为零合并索引操作,这很可能隐藏错误。

    

© www.soinside.com 2019 - 2024. All rights reserved.