groovy - Groovy 中启动的委托(delegate)字段在闭包中变为空

标签 groovy annotations closures

Groovy 版本:2.4.3 JVM:1.8.0_60 供应商:Oracle Corporation 操作系统:Mac OS X

import groovy.transform.*

@Canonical
class A {
    def f() {
        map = [:] //map is not null
        3.times {
            assert map != null // failed, map is null?!
        }
    }

    @Delegate
    Map map
}
new A().f()

当我调用 f() 时,我得到断言失败,这意味着映射为空。但是如果我删除注释“@Delegate”,那么就不会有任何问题。或者如果断言不在闭包中,也没有问题。我的问题是为什么委托(delegate)字段在闭包内或闭包外表现不同?如果是因为闭包中的map与A类中的对象不同,为什么在删除注释后它还能工作?

import groovy.transform.*

@Canonical
class A {
    def f() {
        map = [:]
        3.times {
            assert map != null // No problem, map is not null
        }
    }

    Map map
}
new A().f()

或者

import groovy.transform.*

@Canonical
class A {
    def f() {
        map = [:]
        assert map != null //no problem too
    }

    @Delegate
    Map map
}
new A().f()

最佳答案

当您拥有@Delegate注释时,您的类本质上成为java.util.Map的实现,它将其调用委托(delegate)给它的字段map.断言闭包中对 map 的引用被视为 this.getAt('map') 调用,而不是对 map 字段的引用。由于没有值映射到键 map,因此断言失败。

也许这会让事情变得更清楚:

import groovy.transform.*

@Canonical
class A {
    def f() {
        map = [map:'not null'] // delegated map has key 'map'
        3.times {
            assert map == 'not null'
        }
    }

    @Delegate
    Map map
}
new A().f()

奇怪之处主要与断言是在闭包内完成的这一事实有关,该闭包具有 resolve strategy它规定了如何解析引用,其中包括元类的使用。删除闭包,@Delegate 注释不再产生影响。

import groovy.transform.*

@Canonical
class A {
    def f() {
        assert map != null
    }

    @Delegate
    Map map = [:]
}
new A().f()

关于groovy - Groovy 中启动的委托(delegate)字段在闭包中变为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33035166/

相关文章:

java - Hibernate:如何指定聚簇索引注释

java - Android 反射注解失败

swift - 将过滤器作为参数传递给 Swift 函数?

groovy - Spock中双右箭头运算符(>>)的解释是什么?

groovy - 命名参数

templates - 这个 Play 模板代码可以简化吗(避免 if/else 标签)?

c# - 这些示例是 C# 闭包吗?

javascript - 取消引用变量的闭包有用吗?

groovy - 如何使用 Groovy 添加 XML 属性?