2

にメソッドを追加しましたが、メソッドが呼び出されているインスタンスClosuremetaClass参照を取得できないようです。この例では、は、私が呼び出しているクロージャーdelegateではなく、スクリプトインスタンスに設定されています。ffixedPoint

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はExpandoMetaClassである新しいMetaClassを取得します。そして次のステップでメソッドが追加されます。現在、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

少なくとも私にとって、このコードは例外なく実行されます...

補足:メソッドを形成するためにメタクラスに格納されているクロージャーは、通常、指定したもののクローンです。メタクラスは、コピーにデリゲートを設定します。たとえば、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 に答える