Groovy 全局闭包在嵌套方法调用中不起作用

jan*_*nar 2 groovy closures scope

我有一个简单的闭包,我希望能够在我的代码中使用它来衡量任何其他闭包所需的时间。它看起来像这样:

def benchmark = {name,closure ->
    start = System.currentTimeMillis()
    ret =  closure.call()
    now = System.currentTimeMillis()   println(name + " took: " +  (now - start))
    ret
}
Run Code Online (Sandbox Code Playgroud)

它在从同一范围调用时工作,如下所示:

benchmark('works') { println("Hello, World\n")}
Run Code Online (Sandbox Code Playgroud)

但是当它调用嵌套范围时它似乎不起作用

def nested()
{
   benchmark('doesnt_work'){print("hello")}
}

nested()
Run Code Online (Sandbox Code Playgroud)

tim*_*tes 5

那是因为您在脚本中运行它。

Groovy 将上述内容转换为:

class Script {
    def run() {
        def benchmark = {name,closure -> ...
        nested()
    }

    def nested() {
        benchmark('doesnt_work'){print("hello")}
    }
}
Run Code Online (Sandbox Code Playgroud)

所以如你所见,闭包是隐式run方法的局部,但该nested方法属于类......

我相信你有3个选择:

  1. nested一个闭包,它们都将存在于同一个作用域中

    def benchmark = {name,closure ->
        start = System.currentTimeMillis()
        ret =  closure.call()
        now = System.currentTimeMillis()
        println(name + " took: " +  (now - start))
        ret
    }
    
    def nested = {
       benchmark('doesnt_work'){print("hello")}
    }
    
    nested()
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编写一个合适的类并自己控制范围

    class Test {
        def benchmark = {name,closure ->
            long start = System.currentTimeMillis()
            def ret =  closure.call()
            long now = System.currentTimeMillis()
            println(name + " took: " +  (now - start))
            ret
        }
    
        def nested() {
            benchmark('doesnt_work'){print("hello")}
        }
    
        static main( args ) {
            new Test().nested()
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. @groovy.transform.Fielddef benchmark = {name,closure -> ...此之前添加会将闭包定义向上移动为该 Script 类属性

    @groovy.transform.Field def benchmark = { name, closure ->
        start = System.currentTimeMillis()
        ret =  closure.call()
        now = System.currentTimeMillis()
        println(name + " took: " +  (now - start))
        ret
    }
    
    def nested() {
       benchmark('doesnt_work'){print("hello")}
    }
    
    nested()
    
    Run Code Online (Sandbox Code Playgroud)