将方法添加到Closure

时间:2013-01-27 00:12:36

标签: groovy

我已经为Closure的{​​{1}}添加了一个方法,但我似乎无法获得该方法被调用的实例的引用。在此示例中,metaClass设置为脚本实例,而不是我正在调用delegate的{​​{1}}闭包:

f

给出

Caught: groovy.lang.MissingMethodException: No signature of method: test.call() is applicable for argument types: (java.lang.Integer) values: [9]

我在这做错了什么?

2 个答案:

答案 0 :(得分:4)

说明: 如果你做Closure.metaClass.fixedPoint = ...那么Closure类会得到一个新的MetaClass,它是ExpandoMetaClass。并在下一步中添加该方法。现在Closure的默认元类是ClosureMetaClass,它既不允许你添加方法,也不关心其他元类。当您执行def f = { Math.round(it / 2.0) }时,您实际上创建了一个新类(及其实例)。它扩展了Closure,但不是Closure本身。默认情况下,这个类将具有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

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

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

答案 1 :(得分:0)

问题在于Closure.metaclass{ -> }.metaClass是不同的实例。

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

的产率:

org.codehaus.groovy.runtime.HandleMetaClass@12f5f0d
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass@192d8d6