我已经为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]
我在这做错了什么?
答案 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