Конфликт Groovy между автоматическим получателем свойств, локальными переменными и замыканиями?

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

Известно ли это поведение и есть ли где-нибудь документация, подробно описывающая это? Я потратил много времени, пытаясь понять, что не работает...

Рассмотрим следующий код:

class TestClass {

    def doIt(Closure closure) {
        closure.setDelegate(this)
        closure.call()
    }

    def getRevision() {
        return "testclass revision"
    }
}

def testIt() {
    def revision = "testit revision"

    println "1: " + revision + " (expect: testit)"

    TestClass tester = new TestClass()
    tester.doIt {
        println "2: " + getRevision()  + " (expect: testclass)"
    }

    println "3: " + revision + " (expect: testit)"

    tester.doIt {
        println "4: " + revision + " (expect: testit)"
        revision = getRevision()
        println "5: " + revision + " (expect: testclass)"
        println "6: ${getRevision()} (expect: testclass)"
        println "7: " + getRevision() + " (expect: testclass)"
    }

    // expect to have been set to testclass value in previous closure
    println "8: " + revision + " (expect: testclass)"

    tester.doIt {
        println "9: ${getRevision()} (expect: testclass)"
        println "10: " + getRevision() + " (expect: testclass)"
    }

    println "11: " + revision + " (expect: testclass)"
}

testIt()

Выполнение этого кода приводит к следующему выводу:

1: testit revision (expect: testit)
2: testclass revision (expect: testclass)
3: testit revision (expect: testit)
4: testit revision (expect: testit)
5: testit revision (expect: testclass)
6: testit revision (expect: testclass)
7: testit revision (expect: testclass)
8: testit revision (expect: testclass)
9: testclass revision (expect: testclass)
10: testclass revision (expect: testclass)
11: testit revision (expect: testclass)

Моя основная проблема связана с 5/6/7. Кажется, что простое использование локальной переменной revisionвнутри замыкания «скрывает» метод getRevision()в делегате и заменяет его автоматически -сгенерированным getRevision()в стиле bean-компонента -в соответствии с revision" имущество". Если я не использую переменную revision, вызовы getRevision()не вызывают это поведение компонента.

Будем признательны за любую информацию или ссылки на документацию!

6
задан Will Harris 26 April 2012 в 17:40
поделиться