2013-05-07 4 views
3

Я только что начал программировать и отбирал lua, чтобы написать скрипт, обрабатывающий файл конфигурации XML.Lua объявляет локальную переменную в рекурсивной функции

Загрузите XML-файл с помощью LuaXML (C-привязывающей версии), который сопоставляет его с сильно вложенной таблицей.

Моя проблема возникла, когда я попытался написать функцию, которая находит все совпадения с тегом в 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

+0

Я тестировал производительность двух решений. Оригинальный с функциями обертки выполняется быстрее. Интересно. – workspace

4

На самом деле, я думаю, вы придумали приятное и элегантное решение. Что вы делаете, так это использование этих функций в Lua: closures, это может быть очень полезным при написании рекурсивной функции, которая требует создания структур данных во время работы. Все, что вам нужно сделать, чтобы сделать его идеальным, - добавить локальное ключевое слово перед function findall внутри 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 

Здесь стек вызовов используются для хранения промежуточных результатов, это может дать вам очень большой стек с глубокой рекурсией или нескольких вызовов функции в обратном.

Лучший способ сделать это не называется 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 - локальным. –

+0

Ups, забыли локальное ключевое слово – jbr

+0

Большое спасибо за объяснение. Очень полезно. – workspace

Смежные вопросы