2013-03-25 8 views
26

Mam pytanie dotyczące zasad ustalania zakresu w Groovy. W poniższym fragmencie mam trzy zmienne, a ma zasięg lokalny, b ma zasięg skryptu, a c powinien także uzyskać zasięg skryptu przy użyciu adnotacji @Field.Zakres Groovy - jak uzyskać dostęp do zmiennej skryptowej w metodzie

#!/usr/bin/groovy 
import groovy.transform.Field; 

//println org.codehaus.groovy.runtime.InvokerHelper.getVersion() 

def a = 42; 
b = "Tea" 
@Field def c = "Cheese" 

void func() 
{ 
    // println a // MissingPropertyException 
    println b // prints "Tea" 
    println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6 

} 

class Main 
{ 
    def method() 
    { 
     // println a // MissingPropertyException 
     // println b // MissingPropertyException 
     // println c // MissingPropertyException with both 1.8.6. and 2.1.2 
    } 

} 

func(); 
new Main().method(); 

Otrzymuję MissingPropertyException s na liniach oznaczonych komentarzami. Oczekiwane są wyjątki od a, ponieważ ta zmienna ma zasięg lokalny. Ale oczekiwałbym, że b będzie dostępny wewnątrz method() - tak nie jest. @Field nie robi nic w groovy 1.8.6, chociaż po aktualizacji działa, więc myślę, że to stary błąd. Niemniej jednak, c jest niedostępne wewnątrz method() z żadną wersją.

Więc moje pytania to:

  1. Dlaczego nie mam dostępu do zmiennej opatrzone @Field wewnątrz method()?
  2. Jak mogę odnieść się do zmiennej skryptu wewnątrz method()?

Odpowiedz

25

Gdy masz metody lub instrukcje poza deklaracją class w piskliwym skrypcie, tworzona jest niejawna klasa. Aby odpowiedzieć na Twoje pytania:

  1. W przykładzie func() może uzyskać dostęp do pola c ponieważ obaj są członkami niejawny klasie. Klasa Main nie jest, więc nie może.

  2. Musisz przekazać odwołanie do zmiennej skryptu do method(). Jednym ze sposobów jest przekazanie niejawnie zdefiniowanego obiektu binding, za pomocą którego można uzyskać dostęp do wszystkich zmiennych zakresu skryptu.

Przykład:

#!/usr/bin/groovy 
import groovy.transform.Field; 

//println org.codehaus.groovy.runtime.InvokerHelper.getVersion() 

def a = 42; 
b = "Tea" 
@Field def c = "Cheese" 

void func() 
{ 
    // println a // MissingPropertyException 
    println b // prints "Tea" 
    println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6 

} 

class Main 
{ 
    def scriptObject 
    def binding 

    def method() 
    { 
     // println a // MissingPropertyException 
     println binding.b 
     println scriptObject.c 
    } 
} 

func(); 
new Main(scriptObject: this, binding: binding).method(); 
+0

pewien, że ma na celu przekazać te scriptObject i wiążące argumenty do konstruktora, a la „nowy główny (scriptObject: to, oprawa: wiązanie) .method() " – billjamesdev

+0

Ups, dzięki. Poprawione. – ataylor

9

Ten skrypt i Main generowane są w postaci dwóch oddzielnych klas wewnątrz tego samego pliku.

Jako, że Main nie jest wewnętrzną klasą klasy Script, nie może zobaczyć pola java.lang.Object c wewnątrz klasy skryptu.

Będziesz albo trzeba wyraźnie owinąć ten skrypt w klasie z static main(args) metody (i wewnętrznego Main klasy) albo trzeba by przekazać instancję klasy skryptu metody jak: Main.method(this)

This jest coś takiego, że powyższy skrypt generuje:

class Script032034034 { 
    Object c 

    Script032034034() { 
    c = 'Cheese' 
    } 

    Object run() { 
    Object a = 42 
    b = 'Tea' 
    func() 
    new Main().method() 
    } 

    void func() { 
    println b 
    println c 
    } 
} 

class Main { 
    Object method() { 
    } 
} 
+0

Dzięki za wygenerowany fragment kodu, bardzo pomaga to w zrozumieniu. Moje nieporozumienie było takie, że myślałem, że Main będzie podklasą Script032034034. – amarillion

+0

Naprawdę pomocny kawałek kodu. Dziękuję :) –

+1

W podanym kodzie, w jaki sposób 'func()' "widzisz" 'b'? Czy 'b' jest także własnością klasy Script? –