在 Grails 应用程序中,我试图防止在有向图中创建循环。用户可以为节点分配父节点,但任何节点都不应该是其父节点的祖先。我编写了一个调用 checkLineageForTarget 的简单设置函数,它是执行繁重工作的递归函数:
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 为真,调用函数尝试添加新的父/子关系,而我的堆栈溢出。
我的误解是什么?
最佳答案
each
方法返回调用它的同一个集合,因此 retVal
可能不是 bool 值“true”,但被评估为“真实”(因为它是一个集合,这意味着它不是空的)。
如果要检查集合中每个元素的条件,可以使用 every
.
boolean checkLineageForTarget(Integer target, Collection<Node>stillToProcess){
stillToProcess.every { node ->
node.id != target && checkLineageForTarget(target, getParentNodes(node))
}
}
请注意,我不需要检查父节点集合上的 .empty
条件,因为这将被对 checkLineageForTarget 的递归调用过滤(即调用 .every
在空集合上总是返回 true)。此外,由于 &&
运算符的短路,迭代在 node.id == target
时立即停止 :)
关于grails - 为什么这个 Groovy 闭包没有返回我期望的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9387641/