привязка и отличные закрытия

Я не знаю, как использовать привязку с закрытиями в Groovy. Я записал тестовый код и при выполнении его, это сказало, отсутствующий метод setBinding на закрытии, переданном как параметр.

void testMeasurement() {
    prepareData(someClosure)
}
def someClosure = {
  assertEquals("apple", a)
}


  void prepareData(testCase) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.setBinding(binding)
    testCase.call()

  }
5
задан Kristof U. 15 May 2018 в 12:29
поделиться

2 ответа

У меня это работает с Groovy 1.7.3:

someClosure = {
  assert "apple" == a
}
void testMeasurement() {
  prepareData(someClosure)
}
void prepareData(testCase) {
  def binding = new Binding()
  binding.setVariable("a", "apple")
  testCase.setBinding(binding)
  testCase.call()
}
testMeasurement()

В этом примере сценария вызов setBinding устанавливает a в привязке сценария (как вы можете видеть из документации Closure , вызова setBinding нет). Итак, после вызова setBinding вы можете вызвать

println a

, и он распечатает «яблоко»

. Чтобы сделать это в классе, вы можете установить делегат для закрытия (закрытие вернется к этому делегату, когда свойство не может быть найдено локально), например:

class TestClass {
  void testMeasurement() {
    prepareData(someClosure)
  }

  def someClosure = { ->
    assert "apple" == a
  }

  void prepareData( testCase ) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.delegate = binding
    testCase.call()
  }
}

И оно должно получить значение из a из класса делегата (в данном случае привязки)

Эта страница здесь проходит через использование делегата и области видимости переменных в Closures

Действительно, вместо использования объекта Binding вы должны иметь возможность использовать простую карту вроде этого:

  void prepareData( testCase ) {
    testCase.delegate = [ a:'apple' ]
    testCase.call()
  }

Надеюсь, это поможет!

4
ответ дан 15 December 2019 в 00:48
поделиться

Это действительно странное поведение: удаление "def" перед объявлением someClosure заставляет скрипт работать в JDK1.6 Groovy:1.7.3

Обновление: Это было опубликовано в ответе выше. Моя ошибка в том, что я его повторил. Обновление: Почему это работает? Без def первая строка воспринимается как присвоение свойства, которое вызывает setProperty и делает переменную доступной в связывании, которое решается позже. def должен работать, как и в случае (http://docs.codehaus.org/display/GROOVY/Groovy+Beans)

someClosure = {
    assert "apple", a
    print "Done"
}

void testMeasurement() {
    prepareData(someClosure)
}

void prepareData(testCase) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.setBinding(binding)
    testCase.call()
}
testMeasurement()

Я смог воспроизвести проблему, о которой вы говорите, с помощью следующего кода. Но я не уверен, что это правильный способ использования Binding. В GroovyDocs сказано, что они должны использоваться со скриптами. Не могли бы вы указать мне на документацию, которая предлагает такое использование Binding с Closures.

class TestBinding extends GroovyTestCase {
    void testMeasurement() {
        prepareData(someClosure)
    }

    def someClosure = {
        assertEquals("apple", a)
    }

    void prepareData(testCase) {
        def binding = new Binding()
        binding.setVariable("a", "apple")
        //this.setBinding(binding)
        testCase.setBinding(binding)
        testCase.call()
    }
}

На это был дан ответ в списке рассылки groovy:

В сценарии def foo создаст локальную переменную, а не свойство (приватное поле + геттер/сеттер). Думайте о скрипте примерно так же, как если бы это было тело метода run() или main(). Вот где и как вы можете определить локальные переменные.

0
ответ дан 15 December 2019 в 00:48
поделиться