рекурсия в Groovy (Grails) - PullRequest
       2

рекурсия в Groovy (Grails)

4 голосов
/ 24 июня 2010

Я пытаюсь использовать рекурсию в groovy для обхода дерева отношений.Приведенный ниже код выполняет один цикл, вплоть до childNodes && recurClosure (childNodes), но больше не вызывает замыкание recurClosure.В этот момент у childNodes было два объекта (список массива) того же типа, что и у root.

В коде определено recurClosure и вызовы со списком объектов (root).Затем он перебирает каждый элемент и обрабатывает дочерние узлы (для этого использует grails dsl). Если childNodes не имеет значение null, он рекурсивно вызывает родительский метод.

Должен ли я разбить его, или что-то не так?

def parentval 
def root = Domain.list()

def recurClosure
recurClosure = {inroot ->
  inroot.each {
    returnList << it
    parentval = it
    childNodes = Domain.withCriteria {
      eq('parent', parentval )
    }
  }
  childNodes && recurClosure(childNodes )
}(root)

return returnList

}

спасибо заранее.

Обновление: замечено следующее исключение

    ERROR [2010-06-24 08:20:04,742] [groovy.grails.web.errors.GrailsExceptionResolver] Cannot invoke method call() on null object
java.lang.NullPointerException: Cannot invoke method call() on null object
    at com.bsr.test.DomainService$_closure2_closure7.doCall(com.bsr.test.DomainService:68)
    at com.bsr.test.DomainService$_closure2.doCall(com.bsr.test.DomainService:58)
    at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy:45)
    at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy)
    at org.apache.shiro.web.servlet.ShiroFilter.executeChain(ShiroFilter.java:687)
    at org.apache.shiro.web.servlet.ShiroFilter.doFilterInternal(ShiroFilter.java:616)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:81)
    at java.lang.Thread.run(Thread.java:619)

Обновление 2: сейчас пробует предложение Даниэля.

{ inroot ->
    inroot.each {
        returnList << it
        parentval = it
        childNodes = Domain.withCriteria {
            eq('parent', parentval )
        }
           if(childNodes)
           call(childNodes)
    }
       /*if(childNodes)
        call(childNodes)*/

}(root)

В приведенной выше реализации root является массивом, внутреннее замыкание извлекает из него каждый элемент и рекурсивно вызывает анонимное закрытие.Когда я перемещал 'call' внутри каждого замыкания, он вызывал не внешнее анонимное закрытие, а сам inroot.each {}.Итак, я получаю сообщение об ошибке

ERROR [2010-06-24 08:47:46,438] [groovy.grails.web.errors.GrailsExceptionResolver] instance not of expected entity type: java.util.ArrayList is not a: com.bsr.test.Domain

Я вижу сообщение в блоге о том, как назвать закрытие через 'this' > Я обновлю свои данные .. спасибо

Обновление 3: способ вызова внешнего замыкания - owner.call (childNodes)

Ответы [ 2 ]

10 голосов
/ 24 июня 2010

Проблема в том, что

recurClosure = {
    [...]
}(root)

вы не назначаете закрытие на recurClosure, а вместо возвращаемого значения его вызова!Таким образом, конечно, вы не можете вызвать замыкание через recurClosure() ...

Два возможных решения:

Сначала определите замыкание, а затем вызовите его отдельно, как предложено air_blob:

def recurClosure = {
    [...]
}
recurClosure(root)

Используйте неявную функцию call() для рекурсии.Таким образом, вы можете работать даже с анонимным закрытием.ИМХО, очень хороший способ реализовать рекурсию в Groovy:

{ inroot ->
    inroot.each {
        returnList << it
        parentval = it
        childNodes = Domain.withCriteria {
            eq('parent', parentval )
        }
    }
    if(childNodes)
        call(childNodes)
}(root)

Еще два комментария к вашему коду:

  1. Вы можете объявить returnList: def returnList = []
  2. Хотя childNodes && recurClosure(childNodes ) может делать то, что вы хотите, гораздо удобнее пожертвовать еще одним символом и произнести if ..; -)
  3. Разве вы не хотите рекурсивно вызывать вашзамыкание внутри each?

Еще одно замечание (более высокого уровня) о вашем коде: если родители и их дети относятся к одному и тому же типу (Domain),Domain.list() не вернет ли вообще всех детей тоже?Есть ли необходимость вручную обходить дерево?

2 голосов
/ 24 июня 2010

Есть ли у вас исключения? Вы пытались вызвать его отдельно, как это:

def recurClosure
recurClosure = {inroot ->
  [... stuff ...]
}

recurClosure(root)

Что именно вы хотите сделать в этой строке:

childNodes && recurClosure(childNodes )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...