2011-02-01 7 views
36

Часто желательно объявить константы в верхней части скрипта, на которые можно ссылаться где-либо еще в скрипте. В Groovy кажется, что если вы объявляете константу с использованием final, тогда она недоступна в дочерних областях. Каково решение этого очень простого и общего требования? Обходной путь, который у меня есть сейчас, заключается в создании несвязанной переменной, но это не постоянное и не элегантное.Глобальные константы в Groovy

ответ

60

У Groovy действительно нет глобального масштаба. Когда у вас есть отличный скрипт, который не объявляет класс, он неявно застревает в классе с именем скрипта. Таким образом, конечные переменные в области верхнего уровня - это действительно просто поля неявного класса. Например:

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

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

более или менее эквивалентно:

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 
} 

Это легко понять, почему он не работает расширяется вне. Легкая работа заключается в том, чтобы объявить ваши «глобалы» в фиктивном классе, например, например. Константы, а затем просто сделайте статический импорт на нем. Он работает даже в одном скрипте. Пример:

import static Constants.* 

class Constants { 
    static final MYCONSTANT = "foobar" 
} 

println MYCONSTANT 

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

РЕДАКТИРОВАТЬ:

Кроме того, сценарии немного особый случай. Если вы объявляете переменную без def или любые модификаторы, такие как final (т. Е. Просто используйте ее), она переходит в привязку к скрипту. Так что в этом случае:

CONSTANT = "foobar" 
println "foobar" 

CONSTANT в скрипт шириной связывания, но в:

final CONSTANT = "foobar" 
println "foobar" 

CONSTANT является локальной переменной в методе run() сценария. Более подробную информацию об этом можно найти на https://web-beta.archive.org/web/20150108090004/http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22

+0

Константы должны быть перечислениями в мире Java 1.5+ ... :) – Esko

+6

@Esko каждый тип константы должен быть Enum? Даже что-то вроде GRAVITY или PI? O_o –

+0

@tim_yates: Нет, перечисление должно содержать все константы, которые связаны друг с другом. В вашем примере это будет нечто вроде «CelestialObjectAttributes.GRAVITY» или «MathematicConstants.PI». Они также могут быть импортированы, так что вам не нужно повторять имя перечисления, а перечисления всегда являются глобальными (или глобальными) классами (* или classloader *), что делает их идеальной альтернативой для глобальных констант oldschool. – Esko

18

В Groovy 1.8+, вы можете добиться этого с помощью @Field annotation:

import groovy.transform.Field 

@Field final String MY_CONSTANT = 'constant' 

def printConstant() { println MY_CONSTANT } 

printConstant() 
+1

, но не работает изнутри класса :( – Anentropic

+0

@ Энтропий: не пропустите импорт выше "import groovy.transform.Field" – BTakacs

0

В другой эффективный способ добавить глобальное применение константы уровня являются объявить один интерфейс в подходящем пакете, как

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. 

} 

Использование констант в любом классе, как показано ниже,

import packageNameContainingInterface.applicationConstants // import statement. 
def adminUser = applicationConstants.ADMIN_USER 
println adminUser 
Смежные вопросы