2012-02-22 3 views
3

Grails 애플리케이션에서, 나는 유향 그래프에서 사이클의 생성을 막으려하고있다. 사용자는 노드에 부모를 지정할 수 있지만 노드 자체의 상위 노드는 상위 노드 여야합니다. 나는 무거운 수행하는 재귀 함수입니다 checkLineageForTarget를 호출하는 간단한 설정 기능, 작성했습니다 : 그에서이 (가) 인쇄 "작품"Groovy 클로저가 내가 예상 한 값을 반환하지 않는 이유는 무엇입니까?

boolean checkLineageForTarget(Integer target, Collection<Node>stillToProcess){ 
// true means that this is a safe addition 
// false means that this addition creates a cycle 

    boolean retVal = stillToProcess.each { 
     Collection<Node> itsParents = getParentNodes(it) 

     if (it.id == target){ 
      println("found a loop on " + target); 
      return false; // loop detected! 
     } 
     if (itsParents.empty){ return true; } // end of the line 

     return checkLineageForTarget(target, itsParents) 
    } 

    // at this point, retVal is always true, even when the "found a loop [...]" condition is met 
    return retVal; 
} 

이를 "루프를 발견 [...]"메시지 , 클로저 외부에서는 retVal이 true이고, 호출 함수가 새로운 부모/자식 관계를 추가하려고 시도하고 스택이 끝났습니다.

오해는 무엇입니까?

+0

당신이 .each''사용할 수 있습니다 그렇게? 나는 .every를 사용하고있다. – zoran119

+1

그것은 Grails 다. "Grails on Grails"가 아니다. –

+0

@Burt oops, my bad. –

답변

3

each 메서드는 호출 된 컬렉션과 동일한 컬렉션을 반환하므로 retVal은 아마도 "true"부울이 아니지만 "진리"로 평가됩니다 (콜렉션이므로 빈 상태가 아닙니다).

컬렉션의 모든 요소에 대한 조건을 확인하려면 every을 사용할 수 있습니다. 나는 그가 (즉, 항상 true를 돌려 빈 컬렉션 .every를 호출) checkLineageForTarget에 재귀 호출에 의해 필터링되기 때문에 부모 노드 컬렉션에 .empty 상태를 점검 필요하지 않았다

boolean checkLineageForTarget(Integer target, Collection<Node>stillToProcess){ 
    stillToProcess.every { node -> 
     node.id != target && checkLineageForTarget(target, getParentNodes(node)) 
    } 
} 

참고. 또한 && 연산자의 단락 때문에 node.id == target :

+0

고마워, 그게 큰 개선이야. –

3

.each은 완료 될 때 반복되는 객체를 반환합니다. 이 값을 부울에 할당하면 true으로 강제 변환됩니다. 작업에 .every을 사용하고 싶을 것입니다. 각 반복이 true을 반환하고 처음 false에 도달하면 루핑을 중지 할 경우에만 true을 반환합니다. 자세한 내용은 in the groovy docs을 참조하십시오.

2

클로저 내부로 돌아올 때 메서드 내에서 메서드 호출 내부로 돌아 오는 것과 같습니다.이 메서드는 해당 범위의 로컬이며 클로저가 호출되는 실제 메소드에는 아무런 영향을 미치지 않습니다.이 경우에는 제안 된 다른 접근법 중 하나 (예 : every)를 사용하거나 일반 for 루프를 사용합니다 (Groovy와 동일하게 작동하므로 null- 안전하고 지원하지만 유형을 필요로하지 않습니다)하지만 당신은 루프의 탈옥 또는 반환하고 루프의 실제에있어 이후 메소드에서 반환 할 수 있습니다

boolean checkLineageForTarget(Integer target, Collection<Node>stillToProcess){ 

    for (Node node in stillToProcess) { 
     Collection<Node> itsParents = getParentNodes(node) 
     ... 
    } 
    ... 
} 
관련 문제