如何才能让这个代码段工作?

时间:2009-11-15 18:04:16

标签: groovy metaprogramming eval porting

我想将一小段代码从Ruby移植到Groovy,而我却陷入了困境:

def given(array,closure) {
    closure.delegate = array
    closure()
}

given([1,2,3,4]) {
   findAll { it > 4}
}

现在它已经消失了这条消息:

Exception thrown: Cannot compare ConsoleScript0$_run_closure1 with value 'ConsoleScript0$_run_closure1@1e6743e' and java.lang.Integer with value '4'

我试图将闭包的委托设置为数组,但似乎在findAll方法中,它表示一个闭包,而不是数组中的实际项。我也尝试像这样运行闭包:

array.with {
   closure(array)
}

但我仍然无法使其发挥作用。关于什么可行的任何想法? Ruby的等价物是instance_eval数组上下文中的闭包。

编辑:运行Mykola的代码产生了这个输出:

given [1, 2, 3, 4]
class Demo$_main_closure1
2
Exception thrown: Cannot compare Demo$_main_closure1 with value 'Demo$_main_closure1@fe53cf' and java.lang.Integer with value '2'

groovy.lang.GroovyRuntimeException: Cannot compare Demo$_main_closure1 with value 'Demo$_main_closure1@fe53cf' and java.lang.Integer with value '2'

    at Demo$_main_closure1_closure2.doCall(ConsoleScript3:15)

    at Demo$_main_closure1.doCall(ConsoleScript3:15)

    at Demo$_main_closure1.doCall(ConsoleScript3)

    at Demo.given(ConsoleScript3:28)

    at Demo$given.callStatic(Unknown Source)

    at Demo.main(ConsoleScript3:12)

我正在运行Groovy 1.6.5。

4 个答案:

答案 0 :(得分:1)

对我来说这看起来像个错误。这是代码

class Demo {
   static def main(args) {
      given([1, 2, 3, 4]) {
          println getClass()
          println size()  
          grep { v -> v > 2 }  
      }
   }

   static def size() {
      return 2
   }

   static def given(object, closure) {
       println 'given ' + object

       closure.resolveStrategy = Closure.DELEGATE_ONLY
       closure.delegate = object
       closure()
   }
}

必须打印(我倾向于认为)'4'作为一个尺寸。实际上,如果您要评论方法'大小',它会打印出来。

您可以阅读有关resolveStrategy的内容,然后告诉我们未正确设置的内容。

答案 1 :(得分:1)

简单 - 你试图调用一个闭包传递一个数组,其中findAll应该在数组本身上调用

以下是一些可能的解决方案。第一个是直截了当的:

def given(array,closure) {
    closure(array)
}

println "first way result: " +
given ( [1,2,3,4,5] ) { it.findAll { it > 4 } }

或者您可以将findAll封装在方法体中(这取决于您实际上要做的事情):

def given(array,closure) {
 array.findAll(closure)
}

println "second way result: " + 
given( [1,2,3,4,5] ) { it > 4 }

以下是两者的结果:

first way result: [5]
second way result: [5]

走开了!

答案 2 :(得分:1)

在这种情况下,委托对象是一个java.util.ArrayList对象,它没有forEach方法。

然而,这个类的Groovy包装器有这个方法,但是这里没有使用它(这个接缝是一个bug)。

您可以使用delegate.forEach()解决此问题。我可以看到这打破了你想到的DSL,但也许它会让你更近一步。

以下代码适用于我:

def given(array,closure) {
    closure.delegate = array
    closure()
}

given([1,2,3,4]) {
   delegate.findAll { it > 4}
}

答案 3 :(得分:0)

尝试:

array.with(closure)

或者如果你想保留你的语法:

def given(array,closure) {
    array.with(closure)
}