3

我刚开始编程,选择了lua来写一个处理XML配置文件的脚本。

我使用 LuaXML(C 绑定版本)加载 XML 文件,它将它映射到一个高度嵌套的表。

当我尝试编写一个查找 xmltable 中标记的所有匹配项的函数时,我的问题出现了。匹配项插入到函数返回的表中。我的问题是这个表变量的声明,它必须是本地的。

首先我试过:

local result = result or {}

但这会在每次递归时声明变量。

最后我想出了这个可行的解决方案,但对我来说似乎太复杂了:

function findall_wrapper(xmltable, tag)

  local results = {}

  function findall(xmltable, tag)

    if xml.TAG == tag then table.insert (results, xmltable) end

    for k, v in pairs(xmltable) do
      if (type(v) == "table") then findall(v, tag) end 
    end
  end

  findall(xmltable, tag)
  return results

end

我怎样才能以更好、更优雅的方式解决这个问题?为什么local result = result or {}每次递归都声明变量?

抱歉,如果我的问题的答案太明显了,但正如我所提到的,我刚刚开始编程。

4

2 回答 2

4

实际上,我认为您已经提出了一个不错且优雅的解决方案。您正在做的是利用 Lua 中的函数是闭包,这在编写递归函数时可能是一种非常有用的技术,它需要在运行时构建数据结构。要使其完美,您需要做的就是在function findallinside前面添加 local 关键字function findall_wrapper,然后您的辅助函数将是本地的,并且不会污染全局命名空间。

详细说明一下:

有两种不同类型的函数,简单递归函数和复杂递归函数。所有递归函数都可以通过以下方式实现:

function sum_list(l)
  if #l == 0 then
    return 0
  else
    local e = table.remove(l)
    return e + sum_list(l)
  end
end

print(sum_list({1,2,3,4}))
> 10

这里调用堆栈用于存储中间结果,这可以给你一个非常大的堆栈,深度递归或多次调用返回中的函数。

一种更好的方法称为尾递归

function sum_list(l, a)
  if #l == 0 then
    return a
  else
    local e = table.remove(l)
    return sum_list(l, a + e)
  end
end

print(sum_list({1,2,3,4}), 0)
> 10

在这个例子中,调用中传入了一个累加器,因此调用栈不再用于存储,如果实现支持,可以将其转为迭代。遗憾的是,并非所有递归函数都是尾递归的。在这种情况下,累加器的问题是人们必须将其实例化为零,否则会给出错误的结果。

解决方案就是您所做的:

function sum_list(l)
  local function sum_list_helper(l, a)
    if #l == 0 then
      return a
    else
      local e = table.remove(l)
      return sum_list_helper(l, a + e)
    end
  end

  return sum_list_helper(l, 0)
end

创建本地函数的位置,然后使用正确的实例化值调用该函数。

于 2013-05-07T12:34:52.327 回答
4

如果您的意思是您不想使用包装函数,那么我认为您非常接近。这是你的目标吗?

function findall(xmltable, tag, results)
    local results = results or {}
    if xmltable[xml.TAG] == tag then table.insert(results, xmltable) end
    for k, v in pairs(xmltable) do
      if type(v) == "table" then findall(v, tag, results) end
    end
    return results
end
于 2013-05-07T16:12:14.073 回答