Groovy 在Trait中调用闭包委托时如何正确使用

Groovy 在Trait中调用闭包委托时如何正确使用,groovy,Groovy,我有一个Groovy特性,它需要提供一个配置闭包作为库方法调用的参数(这是HttpBuilder,但不重要) 为了重现该问题,我创建了以下简单示例: trait T { def doIt() { return { n = 1 } } } class Delegate { int n } class Tish implements T { def go() { def closure = d

我有一个Groovy特性,它需要提供一个配置闭包作为库方法调用的参数(这是HttpBuilder,但不重要)

为了重现该问题,我创建了以下简单示例:

trait T {
    def doIt() {
        return {
            n = 1
        }
    }
}

class Delegate {
    int n
}

class Tish implements T {
    def go() {
        def closure = doIt()
        def d = new Delegate()
        closure.delegate = d
        closure()
        assert d.n == 1
    }
}

new Tish().go()
这是因为当运行
T
trait中的
doIt()
方法返回的闭包时,它的委托被设置为可以将
n
变量设置为1的某个对象

但是,这不起作用,我得到以下错误:

 groovy.lang.MissingPropertyException: No such property: n for class: Tish
如果我把
T
作为一个类,让
Tish
扩展它,那么它就可以工作了

我试图改变关闭的委托策略,但没有帮助


这是一个Groovy bug还是有办法解决这个问题?

好吧,我找到了一个解决方法。。。不过,如果知道这是否是一个bug,如果是,Groovy团队将在何时修复它,那将是一件有趣的事情

更新:有望在不久的将来在Groovy版本中修复

在config闭包中进行的所有调用都可以通过调用
getDelegate()
方法获取实际的委托对象,然后直接在其上设置所有属性,如下所示:

return {
    def d = getDelegate()
    d.n = 1
}
不太理想,但让我松了一口气,希望能帮助别人

编辑: 正如@bdkosher在评论中指出的,另一种解决方案是在闭包中使用setter语法:

return {
    setN 1
}
从更改代码

def d = new Delegate()
closure.delegate = d
closure()

这解决了一个非常类似的问题,即我在Grails3.3.8、Groovy2.4.15、Java1.8.0131中遇到的问题。不知道为什么,但这有帮助

我试图找出错误并添加了以下输出

println this
println owner
println delegate

并发现在第一种情况下,即使在执行
closure()
之前设置了
closure.delegate=d
,也没有更改
delegate
!如果调用了
closure.run()
,则
delegate
设置正确

该死!这对Groovy 2.4.5或2.4.7都不起作用。你试过了吗?我不确定这是一个bug,也不确定这是特性应该起作用的方式。如果它确实是一个bug,我可以报告。作为bug报告,因为我现在确信这应该是可行的:我还发现用
setN(1)
替换
n=1
可以让它工作。我刚刚在上面发布的代码中用Groovy 2.4.15尝试了这一点,但它没有工作。甚至
println delegate
doIt
方法中的闭包中也会抛出一个错误。Groovy 2.5.2和最新的3.0-alpha-3都与以前有相同的行为,因此我将接受我的另一个答案,并提供一些可行的解决方法。
println this
println owner
println delegate