2011-02-01 16 views
36

Często deklaruje się stałe na początku skryptu, do którego można się odwoływać w dowolnym miejscu skryptu. W Groovy wygląda na to, że jeśli zadeklarujesz stałą używając final, to nie będzie ona dostępna w zakresach potomnych. Jakie jest rozwiązanie tego bardzo podstawowego i powszechnego wymogu? Obejście, które mam teraz, polega na utworzeniu zmiennej niezwiązanej, ale nie jest ona stała i nie jest elegancka.Globalne stałe w Groovy

Odpowiedz

60

Groovy tak naprawdę nie ma zasięgu globalnego. Kiedy masz fajny skrypt, który nie deklaruje klasy, pośrednio utknie w klasie z nazwą skryptu. Zatem zmienne końcowe w zasięgu najwyższego poziomu są tak naprawdę tylko polami niejawnej klasy. Na przykład:

// foo.groovy 
final MYCONSTANT = "foobar" 
println MYCONSTANT 

class Helper { 
    def hello() { println MYCONSTANT } // won't work 
} 
new Helper().hello() 

jest mniej więcej odpowiednikiem:

class foo { 
    def run() { 
     final MYCONSTANT = "foobar" 
     println MYCONSTANT 
     new Helper().hello() 
    } 
    static main(args) { 
     new foo().run() 
    } 
} 

class Helper { 
    def hello() { println MYCONSTANT } // won't work 
} 

Łatwo zrozumieć, dlaczego to nie działa rozszerzył się. Łatwym zadaniem jest zadeklarowanie swoich "globaliów" w fikcyjnej klasie zwanej np. Stałe, a następnie po prostu wykonaj statyczny import. Działa nawet w jednym skrypcie. Przykład:

import static Constants.* 

class Constants { 
    static final MYCONSTANT = "foobar" 
} 

println MYCONSTANT 

class Helper { 
    def hello() { println MYCONSTANT } // works! 
} 
new Helper().hello() 

EDIT:

Również skrypty są trochę szczególny przypadek. Jeśli zadeklarujesz zmienną bez def lub dowolnych modyfikatorów, takich jak final, (to znaczy po prostu użyj jej), przejdzie ona w powiązanie ze skryptem. Więc w tym przypadku:

CONSTANT = "foobar" 
println "foobar" 

stałych jest w skrypcie całej wiążące, lecz w:

final CONSTANT = "foobar" 
println "foobar" 

stała jest zmienna lokalna w run() metody skryptu. Więcej informacji na ten temat można znaleźć na stronie https://web-beta.archive.org/web/20150108090004/http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22

+0

Stałe powinny być wyliczone w świecie Java 1.5+ ... :) – Esko

+6

@Esko każdy typ stałej powinien być Enum? Nawet coś w rodzaju GRAWITACJI lub PI? O_o –

+0

@tim_yates: Nie, wyliczenie powinno zawierać wszystkie stałe, które są ze sobą powiązane. W twoim przykładzie będzie to coś w stylu 'CelestialObjectAttributes.GRAVITY' lub' MathematicConstants.PI'. Można je również zaimportować, aby nie trzeba było powtarzać nazwy enum, a wyliczenia zawsze są globalne VM (* lub classloader *), co czyni je doskonałą alternatywą dla stałych globalnych oldschool. – Esko

18

W Groovy 1.8+, można to osiągnąć za pomocą @Field annotation:

import groovy.transform.Field 

@Field final String MY_CONSTANT = 'constant' 

def printConstant() { println MY_CONSTANT } 

printConstant() 
+1

nie działa z poziomu klasy :( – Anentropic

+0

@Anentropic: nie przegap importu powyżej "import groovy.transform.Field" – BTakacs

0

The inny skuteczny sposób, aby dodać globalną aplikację stałe poziomie są zadeklarować jeden interfejs w odpowiednim opakowaniu, jak

interface applicationConstants { 
//All constants goes here. 
    static final float PI = 3.14 
    String ADMIN_USER = "ADMIN" 
    Map languages = [ 
     "en": "English", 
     "hi": "Hindi", 
     "mr": "Marathi" 

    ] 
// Like above you can declare all application level code constants here. 

} 

Zastosowanie stałych z dowolnej klasy, jak poniżej,

import packageNameContainingInterface.applicationConstants // import statement. 
def adminUser = applicationConstants.ADMIN_USER 
println adminUser