2013-05-07 75 views
3

我刚开始编程并选择lua编写处理XML配置文件的脚本。Lua在递归函数中声明局部变量

我使用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

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

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 
+0

当然可以!这正是我所缺少的。我必须将变量传递给递归函数。谢谢! – workspace 2013-05-07 17:18:18

+0

我测试了两种解决方案的性能。具有包装功能的原始包装速度更快。有趣。 – workspace 2013-05-07 18:28:04

4

其实我觉得你已经想出了一个不错而优雅的解决方案。你在做什么是利用Lua中的这些函数是closures,在编写递归函数时这可能是一个非常有用的技术,它需要在运行时构建数据结构。您需要做的只是在function findall_wrapperfunction 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 

这里调用堆栈是用来存放中间结果,这可以给你深递归或多次调用的返回功能的非常大的堆栈。

做的更好的方法被称为tail-recursion

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(l, a + e) 
    end 
    end 

    return sum_list_helper(l, 0) 
end 

在其中创建一个本地函数,然后用正确的实例值调用。

+0

sum_list和sum_list_helper都是全局的。要么是本地的,sum_list_help应该是本地的。 – 2013-05-07 13:11:21

+0

Ups,忘记了本地关键字 – jbr 2013-05-07 13:14:18

+0

非常感谢您的解释。很有帮助。 – workspace 2013-05-07 17:18:52