Lua在递归函数中声明局部变量。

我刚开始学习编程并选择使用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 {} 在每个递归中声明变量?

如果我的问题的答案太显然,请原谅,因为我刚开始学习编程。

点赞
用户2195474
用户2195474

实际上,我认为你提出了一个不错和优雅的解决方案。你所做的是利用Lua中的函数是闭包的特性,这在编写需要同时运行时构建数据结构的递归函数时可以是非常有用的技术。要使它完美,你只需要在function findall_wrapper内部的function findall前面添加local关键字,那么你的辅助函数将是局部的,不会污染全局命名空间。

稍作阐述:

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

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-07 12:34:52
用户2279620
用户2279620

如果你的意思是你不想使用一个包装器函数,那么我认为你已经做得非常接近了。这是你的预期吗?

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-07 16:12:14