簡體   English   中英

為什么這個Groovy閉包沒有返回我期望的值?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM