Как я могу заставить этот фрагмент работать? - PullRequest
0 голосов
/ 15 ноября 2009

Я бы хотел портировать небольшой кусочек кода с 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 ]

1 голос
/ 15 ноября 2009

Простой - вы пытаетесь вызвать замыкание, передав ему массив, где 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]

Паз прочь!

1 голос
/ 16 ноября 2009

В этом случае объект делегата является объектом java.util.ArrayList, у которого нет метода forEach.

Тем не менее, у обёртки Groovy для этого класса есть этот метод, но он здесь не используется (это выглядит как ошибка).

Вы можете обойти это, используя delegate.forEach(). Я вижу, что это нарушает DSL, который вы имеете в виду, но, возможно, это делает вас на шаг ближе.

У меня работает следующий код:

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

given([1,2,3,4]) {
   delegate.findAll { it > 4}
}
1 голос
/ 15 ноября 2009

Это похоже на ошибку для меня. Вот код

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' как размер. И на самом деле он печатает, если вы прокомментируете метод size.

Вы можете прочитать больше resolveStrategy, а затем сообщить нам, что не было установлено правильно.

0 голосов
/ 29 декабря 2009

Попробуйте:

array.with(closure)

Или, если вы хотите сохранить синтаксис:

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