2012-08-30 8 views
8

Natknąłem się na coś z Groovy closures i delegatów, że nie jestem pewien, jest oficjalną częścią języka, a może nawet błąd.Aby groovy zamknięcie zmodyfikować zmienną zdefiniowaną w zakresie delegata, należy jawnie określić delegate.theVariableName?

Zasadniczo definiuję zamknięcie, które odczytałem jako ciąg z zewnętrznego źródła, , a jedna ze zmiennych w klasie, która definiuje zamknięcie, musi zostać zmodyfikowana przez zamknięcie. Napisałem prosty przykład pokazujący, co znalazłem działa, a co nie działa.

Jeśli spojrzeć na kodzie testowym poniżej widać klasę, która definiuje zmienną

animal = "cat" 

i dwóch zamknięć określonych w locie z ciągów znaków, które próbują modyfikować zmienną zwierząt.

Działa>

String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }" 

Ale to nie

String code = "{ -> animal = 'bear'; return name + 'xx' ; }" 

Wydaje się, że muszę jednoznacznie zakwalifikować mój do-zmodyfikowaną zmienną 'delegata'. aby to działało. (Domyślam się, że można również zdefiniować program ustawiający w klasie otaczającej dla zamknięcia, aby wywołać, aby zmodyfikować wartość).

Więc .... dowiedziałem się jak to zrobić, ale byłbym zainteresowany, jeśli ktoś mógłby wskazać mi jakiś fajny dokument , który wyjaśnia zasady stojące za tym.

Konkretnie .... dlaczego będzie proste zadanie

animal = 'bear' 

wpływa na zmienną oryginalnego? Czy są tu robione kopie w tle?

import org.junit.Test 

/* 
* Author: cbedford 
* Date: 8/30/12 
* Time: 1:16 PM 
*/ 

class GroovyTest { 
    String animal = "cat" 
    String name = "fred" 

    @Test 
    public void testDelegateWithModificationOfDelegateVariable() { 
    String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }" 
    def shell = new GroovyShell() 
    def closure = shell.evaluate(code) 

    closure.delegate = this 
    def result = closure() 

    println "result is $result" 
    println "animal is $animal" 

    assert animal == 'bear' 
    assert result == 'fredxx' 
    } 


    // This test will FAIL. 
    @Test 
    public void testDelegateWithFailedModificationOfDelegateVariable() { 
    String code = "{ -> animal = 'bear'; return name + 'xx' ; }" 
    def shell = new GroovyShell() 
    def closure = shell.evaluate(code) 

    closure.delegate = this 
    def result = closure() 

    println "result is $result" 
    println "animal is $animal" 

    assert animal == 'bear' 
    assert result == 'fredxx' 
    } 
} 

Odpowiedz

7

Groovy zamknięcia mają five strategies rozwiązywania symboli wewnątrz zamknięcia:

  • OWNER_FIRST: właściciel (gdzie zamknięcie wyżej) jest najpierw, a następnie pełnomocnik
  • OWNER_ONLY: właściciel jest zaznaczone , Delegat jest sprawdzany tylko wtedy, gdy jawnie odwołuje się do niego:
  • DELEGATE_FIRST: delegat jest najpierw sprawdzany, następnie właściciel
  • DELEGATE_ONLY: delegat jest sprawdzana pierwsza, właściciel jest sprawdzane tylko wtedy, gdy odwołuje się wyraźnie
  • TO_SELF: ani delegat ani właściciel są sprawdzane

Domyślnie jest OWNER_FIRST. Ponieważ zamknięcie jest zdefiniowane dynamicznie, właścicielem jest obiekt skryptowy, który sam posiada własne reguły. Zapisanie animal = 'bear' w skrypcie spowoduje utworzenie nowego powiązania o nazwie animal i przypisanie do niego 'bear'.

można naprawić testy do pracy bez wyraźnego odwoływania delegata poprzez zmianę strategii ustępują zamknięcia przed wywołaniem go:

closure.resolveStrategy = Closure.DELEGATE_FIRST 

To pozwoli uniknąć dziwne skryptu wiązania i używać delegata zgodnie z oczekiwaniami .

+0

To ma sens. i też szybko; ^). wielkie dzięki. –

Powiązane problemy