Groovy: какая цель "def" в "def x = 0"?
В следующем фрагменте кода (взятом со страницы Руководства по семантике Groovy) зачем добавлять префикс к ключевому слову def
?
def x = 0
def y = 5
while ( y-- > 0 ) {
println "" + x + " " + y
x++
}
assert x == 5
Ключевое слово def
можно удалить, и этот фрагмент даст те же результаты. Так, каков эффект ключевого слова def
?
Ответы
Ответ 1
Синтаксический сахар для базовых скриптов. Опускание ключевого слова "def" помещает переменную в привязки для текущих script и groovy рассматривает ее (в основном) как переменную с областью видимости:
x = 1
assert x == 1
assert this.binding.getVariable("x") == 1
Использование ключевого слова def вместо этого не помещает переменную в привязки скриптов:
def y = 2
assert y == 2
try {
this.binding.getVariable("y")
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
Отпечатки: "ошибка поймана"
Использование ключевого слова def в больших программах важно, поскольку оно помогает определить область, в которой эта переменная может быть найдена, и может помочь сохранить инкапсуляцию.
Если вы определяете метод в script, он не будет иметь доступа к переменным, которые создаются с помощью "def" в теле основного script, поскольку они не входят в область видимости:
x = 1
def y = 2
public bar() {
assert x == 1
try {
assert y == 2
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
}
bar()
печатает "ошибка поймана"
Переменная "y" не входит в объем внутри функции. "x" находится в области видимости, поскольку groovy проверяет привязки текущего script для переменной. Как я сказал ранее, это просто синтаксический сахар, чтобы быстрее и грязнее писать скрипты (часто один лайнер).
Хорошая практика в больших сценариях - всегда использовать ключевое слово "def" , чтобы вы не сталкивались с проблемами странного охвата или не вмешивались в переменные, которые вы не планируете использовать.
Ответ 2
Тед-ответ отлично подходит для скриптов; Ben answer является стандартным для классов.
Как говорит Бен, подумайте об этом как о "объекте", но он намного круче, поскольку он не ограничивает вас объектными методами. Это имеет неочевидные последствия в отношении импорта.
например. В этом фрагменте я должен импортировать FileChannel
// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*
import java.nio.channels.*
class Foo {
public void bar() {
FileChannel channel = new FileInputStream('Test.groovy').getChannel()
println channel.toString()
}
}
new Foo().bar()
например. Но здесь я могу просто "крыло", если все находится на пути к классу
// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*
class Foo {
public void bar() {
def channel = new FileInputStream('Test.groovy').getChannel()
println channel.toString()
}
}
new Foo().bar()
Ответ 3
В соответствии с этой страница, def
заменяет имя типа и может просто считаться псевдонимом для Object
(т.е. означает, что вы не заботитесь о типе).
Ответ 4
Что касается этого одиночного script, то практической разницы нет.
Однако переменные, определенные с помощью ключевого слова "def" , рассматриваются как локальные переменные, то есть локальные для этого script. Переменные без "def" перед ними сохраняются в так называемом привязке при первом использовании. Вы можете подумать о привязке как общей области хранения для переменных и закрытий, которые должны быть доступны "между" сценариями.
Итак, если у вас есть два сценария и их исполнение с тем же GroovyShell, второй script сможет получить все переменные, которые были установлены в первом script без "def" .
Ответ 5
Причина для "def" заключается в том, чтобы сообщить groovy, что вы намереваетесь создать переменную здесь. Это важно, потому что вы никогда не захотите создать переменную случайно.
Это несколько приемлемо в скриптах (скрипты Groovy и groovysh позволяют вам это делать), но в рабочем коде это одно из самых больших зол, с которым вы можете столкнуться, поэтому вы должны определить переменную с def во всем реальном коде groovy (что-либо внутри класс).
Вот пример того, почему это плохо. Это запустится (без провала утверждения), если вы скопируете следующий код и вставите его в groovysh:
bill = 7
bi1l = bill + 3
assert bill == 7
Эта проблема может занять много времени, чтобы найти и исправить. Даже если она всего один раз в жизни, она все равно будет стоить больше времени, чем явное объявление переменных тысяч раз в течение вашей карьеры. Также становится ясно, где именно это было заявлено, не нужно догадываться.
В неважных сценариях/вводе с консоли (например, в groovy console) это несколько приемлемо, поскольку область действия сценария ограничена. Я думаю, единственная причина, по которой groovy позволяет вам делать это в сценариях, - это поддерживать DSL так, как это делает Ruby (плохой компромисс, если вы спросите меня, но некоторые люди любят DSL)
Ответ 6
Собственно, я не думаю, что он будет вести себя одинаково...
переменные в Groovy все еще требуют объявления, а не декларации TYPED, поскольку правая часть обычно содержит достаточно информации для Groovy для ввода переменной.
Когда я пытаюсь использовать переменную, которую я не объявлял с def или типом, я получаю сообщение об ошибке "Нет такого свойства", поскольку он предполагает, что я использую член класса, содержащего код.