[英]Why is this Groovy closure not returning the value that I expect?
在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
似乎返回完成時循環的Object。 您將此賦值為布爾值,並且它被強制為true
。 您可能希望將.every
用於您的任務。 它返回true
只有當每個迭代返回true
,它將停止當它擊中了第一循環的false
。 您可以在groovy文檔中找到更多信息。
each
方法返回它調用的相同集合,因此retVal
可能不是布爾“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
:)迭代就會停止
當你在Closure中返回時,它就像返回方法中的方法調用 - 它是該范圍的本地調用,並且對調用閉包的實際方法沒有影響。在這種情況下,您可以使用建議的其他方法之一(例如每個)或者使用一個常規for循環,因為它的工作方式與每個Groovy相同(即它是null安全並且支持但不需要類型)但你可以突破循環或返回,因為你在一個真正的for循環它將從方法返回:
boolean checkLineageForTarget(Integer target, Collection<Node>stillToProcess){
for (Node node in stillToProcess) {
Collection<Node> itsParents = getParentNodes(node)
...
}
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.