没有参数memoization的闭包仅适用于call()

时间:2016-11-16 13:55:09

标签: groovy memoization

我正在尝试为另一个类中的一些闭包实现memoization。但我无法使其发挥作用。

使用.call()调用闭包时,Memoization正常工作。但是当我把它称为方法时,它不起作用。

代码:

public class Tester  {

    static main (String[] args){

        Sample sample = new Sample();

        println sample.printer.call();  \\works
        println sample.printer.call();  \\works

        sample = new Sample();

        println sample.printer();  \\does not work
        println sample.printer();  \\does not work
    }
}

class Sample{

    def  printer= {
        println "inside"
        true;
    }.memoize();
}

控制台日志:

inside
true
true
Caught: groovy.lang.MissingMethodException: No signature of method: org.codehaus.groovy.runtime.memoize.Memoize$MemoizeFunction.doCall() is applicable for argument types: () values: []
Possible solutions: call(), call([Ljava.lang.Object;), call(java.lang.Object), call([Ljava.lang.Object;), equals(java.lang.Object), isCase(java.lang.Object)
groovy.lang.MissingMethodException: No signature of method: org.codehaus.groovy.runtime.memoize.Memoize$MemoizeFunction.doCall() is applicable for argument types: () values: []
Possible solutions: call(), call([Ljava.lang.Object;), call(java.lang.Object), call([Ljava.lang.Object;), equals(java.lang.Object), isCase(java.lang.Object)
    at Tester.main(Tester.groovy:12)

由于这个原因,我现在必须使用call()更改所有的闭包调用。如果我的正常方法调用能够实现同样的目的,请告诉我。

1 个答案:

答案 0 :(得分:1)

我希望能够提供一个解决方案,但我能做的最好的就是告诉你快速浏览(并尝试使用groovyConsole)让我:

直接在本地memoized闭包上使用短语法进行闭包调用就像魅力一样:

def memclosure = { println "foo" }.memoize()
memclosure()
memclosure()

所以,它与方式有关,Groovy解决了

sample.printer()

实际上,由于此类上没有方法“printer”,因此触发对象metaClass(或默认情况下为“invokeMethod”)的“methodMissing”,然后查看是否存在该方法的属性name,然后对其值执行“doCall”操作(向我看Groovy错误:在Groovy 2.4.4中,它位于MetaClassImpl第1249行

这里的问题是,并非所有的闭包实现都提供了这个doCall方法:ComposedClosure,IteratorClosureAdapter和MethodClosure,例如:确实提供了一个doCall,但Memoize中的对象却没有。

也许某人有更好的解释和/或解决方案(除了提出错误罚单)

我通过在运行时将“doCall”方法附加到memoized闭包的metaClass来实现它:

def dummy = { println "never called" }.memoize()
dummy.class.metaClass.doCall = { -> delegate.call() }
dummy.class.metaClass.doCall = { a -> delegate.call(a) }
dummy.class.metaClass.doCall = { a, b -> delegate.call(a, b) }
dummy.class.metaClass.doCall = { a, b, c -> delegate.call(a, b, c) }
// can you attach new methods to a metaClass with dynamic parameter count?

或许尝试在开始时以某种方式执行该操作并查看这是否是可行的解决方法