简体   繁体   中英

Recursion in Groovy with closure

I am currently trying to understand a problem with recursion. This code checks to see if a node is a leaf node, if it is it will increment the amount of leaf nodes.

I can't understand what the fn.call(this) does and then how it then calls the closure inside the for loop.

Here is my code.

class TreeNode {
    String name
    List<TreeNode> children = []

    // if no children, there is no leaf node
    boolean isLeaf() {
        return !children
    }

    void walkTree(Closure fn) {
        fn.call(this)
        for (child in children) {
            child.walkTree(fn)
        }
    }

}

testTreeNode = new TreeNode(name: "Fred", children: [
            new TreeNode(name: "Janet", children: [
                    new TreeNode(name: "Mark"),
                    new TreeNode(name: "Anne", children: [new TreeNode(name: "Simon") ]),
                    new TreeNode(name: "Kelly")
            ]),
            new TreeNode(name: "Nigel")
    ])

   def leafCount = 0

  testTreeNode.walkTree { node -> if (node.leaf) leafCount++}

I hope I'm following correctly, but it seems you have 2 questions:

1. What does fn.call(this) do?

Firstly, a Closure is an anonymous block of code that can be executed at a later time.

When you call testTreeNode.walkTree , you are passing the Closure (block of anonymous code) node -> if (node.leaf) leafCount++ as a parameter of the walkTree method, so that closure becomes the variable named fn within the context of walkTree .

Within the walkTree method, the Closure (block of code) is then being explicitly invoked using the Closure.call(args) method.

See: http://groovy-lang.org/closures.html#_calling_a_closure

2. How is the closure executed inside the for loop?

As the closure can be referred to using the fn variable name, you are then able to pass that as an argument directly to walkTree for each child TreeNode in the loop, which then invokes that closure using fn.call(this) .

If we substitute the Closure usage with the block of code passed, it might be clearer what is happening:

void walkTree(Closure fn) {
    //Closure executed here
    if (this.leaf) leafCount++

    for (child in children) {
        //closure passed as argument to walkTree method of child TreeNodes
        child.walkTree { node -> if (node.leaf) leafCount++ }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM