Groovy: какова цель "def" в "def x = 0"? - PullRequest
167 голосов
/ 08 октября 2008

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

def x = 0
def y = 5

while ( y-- > 0 ) {
    println "" + x + " " + y
    x++
}

assert x == 5

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

Ответы [ 6 ]

261 голосов
/ 09 октября 2008

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

35 голосов
/ 11 октября 2008

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

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

например. В этом фрагменте я должен импортировать 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()
29 голосов
/ 08 октября 2008

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

12 голосов
/ 14 октября 2008

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

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

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

7 голосов
/ 03 августа 2013

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

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

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

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

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

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

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

5 голосов
/ 08 октября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...