Использование функции `оценка`. Почему это не работает?

Этот код:

evaluate ("def test() { println \"Test is successful!\" }")
test()

приводит к исключению:

FATAL: Нет сигнатуры метода: script1409644336796288198097.test() применим для типов аргументов:() values: [] Возможные решения: use ([Ljava.lang.Object;), getAt (java.lang.String), используйте (java.util.List, groovy.lang.Closure), используйте (java.lang.Class, groovy.lang.Closure), wait(), wait (long) groovy.lang.MissingMethodException: Нет сигнатуры метода: script1409644336796288198097.test() применим для типов аргументов:() values: [] Возможные решения: use ([Ljava.lang.Object;), getAt (java.lang.String), используйте (java.util.List, groovy.lang.Closure), используйте (java.lang.Class, groovy.lang.Closure), wait(), wait (long)     на org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)...

Что я делаю неправильно?

Ответ 1

Результаты оценки script равны нулю. Вы должны либо что-то вернуть, либо выполнить script и вернуть результат.

Пример, возвращающий замыкание вместо определения метода:

test = evaluate ('return { "Test is successful!" }')
assert test() == "Test is successful!"

И пример, когда script выполняет сам метод:

result = evaluate 'def test() { "eval test" }; return test()'
assert result == "eval test"

Если вы не можете изменить код script, вы можете разобрать класс из script, создать новый объект, а затем выполните метод test():

def parent = getClass().getClassLoader()
def loader = new GroovyClassLoader(parent)
def clazz = loader.parseClass('def test() { "new class definition" }');

obj = clazz.newInstance()
assert obj.test() == "new class definition"

Ответ 2

Вы можете сделать это, используя ExpandoMetaClass, чтобы добавить динамические закрытия в свой собственный класс. Вам нужно будет сначала проанализировать строку, чтобы разбить ее на имя функции, аргументы и код.

methodName = "test"
methodArgs = []
methodCode = """println "Hello World!" """

this.metaClass."$methodName"{ code, args ->
  evaluate(code)
}

Затем вы можете вызвать его, выполнив:

"$methodName"(code, arguments)

или

test(code, arguments)

Чтобы получить вывод Hello World!

Подробнее о ExpandoMetaClass вы можете узнать здесь http://groovy.codehaus.org/ExpandoMetaClass

Ответ 3

Если переменная имеет необъявленный тип, то она переходит в привязку script. Связывание видимо для всех методов, которые означают совместное использование данных.

evaluate() является вспомогательным методом, позволяющим динамическую оценку выражений groovy с использованием связывания сценариев this в качестве области переменных.

В привязке переменных вы можете объявить закрытие, которое не принимает аргументов и должно быть ограничено вызовами без аргументов.

С учетом всего этого, ваш script работает по назначению.

evaluate ("test = { -> println \"Test is successful!\" }")
test()

Ответ 4

В дополнение ко всем другим ответам, если вы не хотите изменять структуру своего кода, вы можете просто использовать return this в конце groovy -string:

lib = evaluate ("def test() { println \"Test is successful!\" }; return this")
lib.test()