Groovy: в чем цель «def» в «def x = 0»?

В следующем fragmentе кода (взятом из страницы руководства Groovy Semantics ), почему префикс присваивания ключевым словом def ?

 def x = 0 def y = 5 while ( y-- > 0 ) { println "" + x + " " + y x++ } assert x == 5 

Ключевое слово def можно удалить, и этот fragment даст те же результаты. Итак, каков эффект ключевого слова def ?

    Это синтаксический сахар для базовых скриптов. Опуская ключевое слово «def» помещает переменную в привязки для текущего скрипта, а 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 в больших программах важно, поскольку оно помогает определить область, в которой эта переменная может быть найдена, и может помочь сохранить инкапсуляцию.

    Если вы определите метод в своем скрипте, он не будет иметь доступ к переменным, которые создаются с помощью «def» в теле основного сценария, поскольку они не входят в область видимости:

      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 проверяет привязки текущего скрипта для переменной. Как я сказал ранее, это просто синтаксический сахар, чтобы быстрее и грязнее писать скрипты (часто один лайнер).

    Хорошая практика в больших сценариях – всегда использовать ключевое слово «def», чтобы вы не сталкивались с проблемами странного охвата или не вмешивались в переменные, которые вы не собираетесь использовать.

    Ответ Теда отлично подходит для скриптов; Ответ Бена является стандартным для занятий.

    Как говорит Бен, подумайте об этом как о «объекте», но он намного круче, поскольку он не ограничивает вас объектными методами. Это имеет неочевидные последствия в отношении импорта.

    например, в этом fragmentе я должен импортировать 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() 

    например, но здесь я могу просто «крыло», пока все находится на пути к classам

     // 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() 

    Согласно этой странице def является заменой имени типа и может просто считаться псевдонимом для Object (т. Е. Означает, что вы не заботитесь о типе).

    Что касается этого единственного сценария, нет никакой практической разницы.

    Однако переменные, определенные с использованием ключевого слова «def», рассматриваются как локальные переменные, то есть локальные для этого сценария. Переменные без «def» перед ними сохраняются в так называемом привязке при первом использовании. Вы можете думать о привязке как общей области хранения для переменных и закрытий, которые должны быть доступны «между» сценариями.

    Итак, если у вас есть два сценария и их исполнение с тем же GroovyShell, второй скрипт сможет получить все переменные, которые были установлены в первом скрипте без «def».

    Самое главное, что вы действительно действительно не каждый хотите создать переменную случайно. В сценариях есть что-то вроде ОК, чтобы иметь переменные, созданные по заданию, но в производственном коде это одно из самых больших зол, с которыми вы можете столкнуться. Я не буду рассматривать какой-либо langauge, который позволил бы этой конструкции использоваться в производственном коде.

    Я взял интервью у более чем одного места, где использовал визуальный базис, где они задавали вопрос «Что является первой строкой в ​​любом VB-файле», и если вы не ответили «OPTION EXPLICIT», интервью остановилось прямо там. (OPTION EXPLICIT запрещает создание переменных через назначение в VB и заставляет явное «тусклое»)

    Вот пример того, почему это плохо. Это будет работать (без сбоев assert), если вы скопируете следующий код и вставьте его в строгий скрипт:

     bill = 7 bi1l = bill + 3 assert bill == 7 

    Он также удаляет некоторые возможности компилятора, чтобы помочь вам в рефакторе. Например, если вы переименуете место, в котором вы впервые используете эту переменную, как компилятор знает, чтобы сказать вам, является ли второе использование (назначение) теперь ошибкой, а не новой переменной?

    Дерьмо, как это слишком опасно. Даже если он только укусит вас однажды в вашей жизни, он все равно будет стоить больше времени, чем явно указывать переменные тысячи раз на протяжении всей вашей карьеры. Это также становится очевидным для глаз, только там, где оно развязывается, вам не нужно гадать.

    В сценариях это довольно хорошо, потому что область действия сценария ограничена, и они не используются повторно и не поддерживаются так сильно, как переписываются, но язык, который позволяет создавать при назначении, просто не готов к производству.

    На самом деле, я не думаю, что это будет вести себя одинаково …

    переменные в Groovy по-прежнему требуют объявления, а не декларации TYPED, поскольку правая часть обычно содержит достаточную информацию для Groovy для ввода переменной.

    Когда я пытаюсь использовать переменную, которую я не объявлял с def или типом, я получаю сообщение об ошибке «Нет такого свойства», поскольку он предполагает, что я использую член classа, содержащего код.

    Давайте будем гением компьютера.