Groovy resolStrategy во вложенном замыкании - PullRequest
0 голосов
/ 11 октября 2019

Я ломаю голову над стратегией делегирования Groovy во вложенных замыканиях. Вот упрощенный пример:

class Clazz {
    String name
    String whoAmI() {
        return name
    }
    void doit(Clazz clazz) {
        def cl = {
            println "Outer closure: resolveStrategy=${resolveStrategy}, " +
                    "implicit=${whoAmI()}, delegated=${delegate.whoAmI()}"
            {->
                println "Inner closure: resolveStrategy=${resolveStrategy}, " +
                        "implicit=${whoAmI()}, delegated=${delegate.whoAmI()}"
            }.call()
        }
        cl.resolveStrategy = Closure.DELEGATE_FIRST
        cl.delegate = clazz
        cl()
    }
}

def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)

Вывод:

Внешнее закрытие: resolStrategy = 1, неявное = B, делегированное = B

Внутреннее закрытие: resolStrategy= 0, неявный = A, делегированный = B

Почему resolStrategy не распространяется на внутреннее замыкание? Смысл установки стратегии разрешения состоит в том, чтобы изменить способ неявного разрешения этого . Но если он не распространяется внутри замкнутого пространства, то этот механизм кажется бесполезным. Закрытия настолько распространены в Groovy, что вряд ли можно написать пару строк без них.

1 Ответ

1 голос
/ 12 октября 2019

Нашел похожий вопрос почти пятилетней давности: Различное разрешение вложенного замыкания между методами и свойствами? Видимо, это ошибка, и с тех пор она была открыта без каких-либо изменений: https://issues.apache.org/jira/browse/GROOVY-7232

Связанный пост отмечает кое-что, что я также заметил: свойства правильно разрешены делегату, но не вызовы методов. Вот переработанный пример, демонстрирующий это:

class Clazz {
    String name

    void doit(Clazz clazz) {
        def cl = {
            println "Outer closure: property=${name}, method=${getName()}"
            {->
                println "Inner closure: property=${name}, method=${getName()}"
            }.call()
        }
        cl.resolveStrategy = Closure.DELEGATE_FIRST
        cl.delegate = clazz
        cl()
    }
}

def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)

Результат:

Outer closure: property=B, method=B
Inner closure: property=B, method=A

Кто-то в связанном посте опубликовал обходной путь, используя регидрат . В моем случае это работает (вроде) только в том случае, если заменены все ссылки, включая this !

class Clazz {
    String name

    void doit(Clazz clazz) {
        def cl = {
            println "Outer closure: property=${name}, method=${getName()}"
            {->
                println "Inner closure: property=${name}, method=${getName()}"
            }.call()
        }
        cl.rehydrate(clazz, clazz, clazz)()
    }
}

def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)

Результат:

Outer closure: property=B, method=B
Inner closure: property=B, method=B
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...