Groovy 关闭检查导致意外堆栈溢出错误

Groovy 关闭检查导致意外堆栈溢出错误,groovy,closures,stack-overflow,Groovy,Closures,Stack Overflow,我试图使用此代码更好地理解this、owner和delegate如何在Groovy闭包中工作: class GroovyTest { static void main(String[] args) { examine() { println 'In first closure' println "class is ${getClass().name}" println "

我试图使用此代码更好地理解
this
owner
delegate
如何在Groovy闭包中工作:

class GroovyTest {
    static void main(String[] args) {
        examine() {
            println 'In first closure'
            println "class is ${getClass().name}"
            println "this is $this, super: ${this.getClass().getSuperclass().name}"
            println "owner is $owner, super: ${owner.getClass().getSuperclass().name}"
            println "delegate is $delegate, super: ${delegate.getClass().getSuperclass().name}"

            examine() {
                println 'In closure within the closure'
                println "class is ${getClass().name}"
                println "this is $this, super: ${this.getClass().getSuperclass().name}"
                println "owner is $owner, super: ${owner.getClass().getSuperclass().name}"
                println "delegate is $delegate, super: ${delegate.getClass().getSuperclass().name}"
            }
        }
    }

    static examine(closure) {
        closure()
    }
}
当我执行这段代码时,它会导致堆栈溢出错误,但是我很难找出导致无限递归的原因。我在这里包括堆栈跟踪的一部分:

Caught: java.lang.StackOverflowError
java.lang.StackOverflowError
    at GroovyTest$_main_closure1.doCall(GroovyTest.groovy:10)
    at jdk.internal.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at GroovyTest$_main_closure1$_closure2.doCall(GroovyTest.groovy:14)
    at GroovyTest$_main_closure1$_closure2.doCall(GroovyTest.groovy)
    at jdk.internal.reflect.GeneratedMethodAccessor8.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at GroovyTest.examine(GroovyTest.groovy:21)
    at jdk.internal.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at GroovyTest$_main_closure1.doCall(GroovyTest.groovy:10)
    at jdk.internal.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at GroovyTest$_main_closure1$_closure2.doCall(GroovyTest.groovy:14)
    at GroovyTest$_main_closure1$_closure2.doCall(GroovyTest.groovy)
    at jdk.internal.reflect.GeneratedMethodAccessor8.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at GroovyTest.examine(GroovyTest.groovy:21)
似乎行
println“owner是$owner,super:${owner.getClass().getSuperclass().name}”
导致了无限递归

为什么这段代码会导致堆栈溢出错误,我可以做些什么来修复它

编辑:以下脚本也包含嵌套闭包,完全按照预期工作。堆栈溢出异常不是由嵌套闭包本身引起的。这似乎与打印声明有关

def examiningClosure(closure) {
  closure()
}

examiningClosure() { 
  println "In First Closure:"
  println "class is " + getClass().name
  println "this is " + this + ", super:" + this.getClass().superclass.name
  println "owner is " + owner + ", super:" + owner.getClass().superclass.name
  println "delegate is " + delegate +
              ", super:" + delegate.getClass().superclass.name
  
  examiningClosure() { 
    println "In Closure within the First Closure:"
    println "class is " + getClass().name
    println "this is " + this + ", super:" + this.getClass().superclass.name
    println "owner is " + owner + ", super:" + owner.getClass().superclass.name
    println "delegate is " + delegate +
                ", super:" + delegate.getClass().superclass.name
  }  
}

好的,我首先要为没有花时间仔细调查此事道歉

我会试图用实际的解释来弥补

结果显示以下代码:

def c = {
  println "foo"
}

println "${c}"
有些不直观的结果是执行闭包,而不是在std out上打印闭包的字符串表示:

─➤ groovy test.groovy
foo
因此,在您的示例中:

class GroovyTest {
    static void main(args) {
        examine { // closure 1
            examine { // closure 2
                println "${owner}"
            }
        }
    }

    static examine(closure) {
        closure()
    }
}
(可以省略
检查
方法调用后的参数)

最里面的闭包的所有者是最里面的闭包本身。调用封闭闭包将导致自调用的无限递归,并最终导致
StackOverflowException

例如,您可以通过执行
println“${owner.getClass()}”
来解决此问题,这会阻止隐式闭包调用


我不得不说,来自
“${closure}”
的闭包调用非常不直观,完全不是我所期望的……在多年使用groovy之后……但它确实存在。

您在
检查
中已经执行的闭包中调用
检查
,从而导致无限深度的递归。这或多或少就是
StackOverflowException
的定义。如果删除第二个呼叫,它应该会消失。也就是说,您运行
examine
它调用
examine
它再次调用
examine
它再次无限地调用
examine
。@MatiasBjarand第一个闭包只调用第二个闭包。为什么这必然会导致堆栈溢出错误?这封信中没有任何内容可以说明问题。第一个方法调用包含一个闭包,该闭包包含第二个方法调用。第二个嵌套的方法调用本身不包含方法调用,因此它应该以此结束。Groovy允许嵌套闭包。这不是导致错误的原因。堆栈跟踪表明问题与此行有关:
println“owner是$owner,super:${owner.getClass().getSuperclass().name}”
FYI。。。您的问题场景可以简化很多,使问题更容易处理。看,这个文件中的案例就是我们在这里看到的例子吗。或者这是别的什么?