Поиск списка / карты свободных переменных в замыкании в Groovy
Это мой простой отличный сценарий;
def fourtify(String str) {
def clsr = {
str*4
}
return clsr
}
def c = fourtify("aa")
println("binding variables: ${c.getBinding().getVariables()}")
...
Все, что я пытаюсь сделать здесь, это получить доступ к свободной переменной "str
"Использование экземпляра замыкания, чтобы понять, как замыкание работает за кулисами немного лучше. Как, возможно, в Python locals()
метод.
Есть ли способ сделать это?
2 ответа
Определенное вами замыкание ничего не хранит в binding
объект - он просто возвращает строку, переданную как str
переменная, повторяется 4 раза.
это binding
объект хранит все переменные, которые были определены без указания их типов или использования def
ключевое слово. Это делается через функцию метапрограммирования Groovy (getProperty
а также setProperty
методы, чтобы быть более конкретным). Поэтому, когда вы определяете переменную s
лайк:
def clsr = {
s = str*4
return s
}
тогда это закрытие создаст привязку с ключом s
и значение оценивается из выражения str * 4
, Этот связующий объект является ничем иным, как картой, доступ к которой осуществляется через getProperty
а также setProperty
метод. Так что когда Groovy выполняет s = str * 4
это вызывает setProperty('s', str * 4)
потому что переменная / свойство s
не определено. Если мы сделаем немного простое изменение, как:
def clsr = {
def s = str*4 // or String s = str * 4
return s
}
затем связывание s
не будет создан, потому что setProperty
метод не выполняется.
Еще один комментарий к вашему примеру. Если вы хотите увидеть что-либо в объекте привязки, вам нужно вызвать возвращаемое закрытие. В приведенном выше примере возвращаемое замыкание возвращается, но оно никогда не вызывается. Если вы делаете:
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
тогда вызывается ваше замыкание, и объект привязки будет содержать привязки (если они есть). Теперь, если вы измените свой пример на что-то вроде этого:
def fourtify(String str) {
def clsr = {
def n = 4 // it does not get stored as binding
s = str * n
return s
}
return clsr
}
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
в ответ вы увидите следующий вывод:
binding variables: [args:[], s:aaaaaaaa]
Надеюсь, поможет.
В вашем примере str
является параметром метода / функции fortify
однако, возможно, следующий пример даст вам лучшее понимание Закрытия:
def c={ String s,int x-> return s*x }
println( c.getClass().getSuperclass() ) // groovy.lang.Closure
println( c.getMaximumNumberOfParameters() ) // 2
println( c.getParameterTypes() ) // [class java.lang.String, int]
locals()
Функция Python лучше соответствует groovy.lang.Script.getBinding()
и вот простой пример со скриптом:
Script scr = new GroovyShell().parse('''
println this.getBinding().getVariables() // print "s" and "x"
z = s*(x+1) // declare a new script-level var "z"
println this.getBinding().getVariables() // print "s", "x", and "z"
return s*x
''')
scr.setBinding( new Binding([
"s":"ab",
"x":4
]) )
println scr.run() // abababab
println scr.getBinding().getVariables() // print "s", "x", and "z"