Groovy 在Trait中调用闭包委托时如何正确使用
我有一个Groovy特性,它需要提供一个配置闭包作为库方法调用的参数(这是HttpBuilder,但不重要) 为了重现该问题,我创建了以下简单示例: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
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