2

我已经向Closure's添加了一个方法metaClass,但我似乎无法获得正在调用该方法的实例的引用。在此示例中,delegate设置为脚本实例,而不是f我正在调用的闭包fixedPoint

Closure.metaClass.fixedPoint = {
    while (it != (it = delegate.call(it))) {}
    it
}
def f = { Math.round(it / 2.0) }
println f.fixedPoint(9)

捕获:groovy.lang.MissingMethodException:没有方法签名:test.call() 适用于参数类型:(java.lang.Integer) 值:[9]

我在这里做错了什么?

4

2 回答 2

4

解释:如果你这样做了,Closure.metaClass.fixedPoint = ...那么类 Closure 将获得一个新的 MetaClass,即 ExpandoMetaClass。并且在下一步中添加该方法。现在闭包的默认元类是 ClosureMetaClass,它既不允许你添加方法,也不太关心其他元类。当你这样做时def f = { Math.round(it / 2.0) },你实际上创建了一个新类(及其实例)。它扩展了闭包,但不是闭包本身。这个类默认将 ClosureMetaClass 作为元类,完全忽略了你对 Closure 的元类所做的事情。

解决方案:您必须强制使用 ExpandoMetaClass,因此代码的第一行(在分配 f 之前)应该是ExpandoMetaClass.enableGlobally()

ExpandoMetaClass.enableGlobally()
Closure.metaClass.fixedPoint = {     
  while (it != (it = delegate.call(it))) {}     
  it
}

def f = { Math.round(it / 2.0) } 
assert f.fixedPoint(9) == 1

至少对我来说,这段代码毫无例外地运行......

旁注:存储在元类中以形成方法的闭包通常是您提供的内容的克隆。然后元类将在副本上设置委托。例如,检查 f 的委托println f.@delegate不会向您显示结果。

于 2013-02-05T12:18:45.693 回答
0

问题是,Closure.metaclass并且{ -> }.metaClass是不同的实例。

println (Closure.metaClass)
println ({ -> }.metaClass)

产量:

org.codehaus.groovy.runtime.HandleMetaClass@12f5f0d
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass@192d8d6
于 2013-01-27T07:55:56.113 回答