问题描述
我已经添加了一个方法到 Closure
的 metaClass
,但我似乎无法以获取该方法被调用的实例的引用。在这个例子中,委托
被设置为脚本实例,而不是 f
闭包我调用 fixedPoint
on:
I've added a method to Closure
's metaClass
, but I don't seem to be able to get a reference for the instance the method is being called on. In this example, delegate
is set to the script instance, not the f
closure i'm invoking fixedPoint
on:
Closure.metaClass.fixedPoint = {
while (it != (it = delegate.call(it))) {}
it
}
def f = { Math.round(it / 2.0) }
println f.fixedPoint(9)
给出
gives
Caught: groovy.lang.MissingMethodException: No signature of method: test.call() is applicable for argument types: (java.lang.Integer) values: [9]
我在这里做错了什么?
What a I doing wrong here?
推荐答案
解释:
如果您执行 Closure.metaClass.fixedPoint = ...
然后类Closure将得到一个新的MetaClass,它是ExpandoMetaClass。然后在下一步中添加该方法。现在Closure的默认元类是ClosureMetaClass,它既不允许你添加方法,也不关心其他元类。当你做 def f = {Math.round(it / 2.0)}
时,你实际上创建了一个新的类(和它的实例)。它扩展了Closure,但不是Closure本身。这个类将默认使用ClosureMetaClass作为元类,完全忽略了你对Closure的元类所做的事情。
Explanation:If you do Closure.metaClass.fixedPoint = ...
then the class Closure will get a new MetaClass, which is ExpandoMetaClass. And in a next step the method is added. Now the default meta class for a Closure is ClosureMetaClass, which neither allows you to add methods, nor does it care about other meta classes much. When you do def f = { Math.round(it / 2.0) }
then you actually create a new class (and instance of it). It extends Closure, but is not Closure itself. And this class will have by default ClosureMetaClass as meta class, totally ignoring what you did with the meta class of 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
至少对我来说,这段代码无一例外地运行着......
At least for me this code runs without exception...
边注:
存储在元类中的Closure形成该方法通常是您输入内容的克隆。然后元类将设置副本上的委托。通过例如 println f。@ delegate
检查f的委托,将不会向您显示结果。
Side Note:The Closure stored in the meta class to form the method is usually a clone of what you gave in. The meta class will then set the delegate on the copy. Inspecting the delegate of f by for example println f.@delegate
won't show you the result then.
这篇关于将方法添加到Closure的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!