Add method to Closure

前端 未结 2 1744
Happy的楠姐
Happy的楠姐 2021-01-15 16:17

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 th

相关标签:
2条回答
  • 2021-01-15 16:31

    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.

    Solution: You have to force the usage of ExpandoMetaClass, thus the first line of your code (before f is assigned) should be 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...

    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.

    0 讨论(0)
  • 2021-01-15 16:43

    The problem is that Closure.metaclass and { -> }.metaClass are the different instances.

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

    yields:

    org.codehaus.groovy.runtime.HandleMetaClass@12f5f0d
    org.codehaus.groovy.runtime.metaclass.ClosureMetaClass@192d8d6
    
    0 讨论(0)
提交回复
热议问题