Поиск списка / карты свободных переменных в замыкании в 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"
Другие вопросы по тегам