web-dev-qa-db-fra.com

Groovy: quel est le but de "def" dans "def x = 0"?

Dans le morceau de code suivant (tiré de la page du manuel Groovy Semantics ), pourquoi préfixer l'affectation avec le mot clé def?

def x = 0
def y = 5

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

assert x == 5

Le mot clé def peut être supprimé et cet extrait produira les mêmes résultats. Alors, quel est l’effet du mot clé def?

172
Leonel

C'est le sucre syntaxique pour les scripts de base. L'omission du mot clé "def" place la variable dans les liaisons du script actuel et la traite (principalement) comme une variable globalement définie:

x = 1
assert x == 1
assert this.binding.getVariable("x") == 1

Utiliser le mot clé def à la place ne met pas la variable dans les liaisons de scripts:

def y = 2

assert y == 2

try {
    this.binding.getVariable("y") 
} catch (groovy.lang.MissingPropertyException e) {
    println "error caught"
} 

Impressions: "erreur interceptée"

L'utilisation du mot clé def dans des programmes plus importants est importante car elle permet de définir la portée dans laquelle la variable peut être trouvée et de préserver l'encapsulation.

Si vous définissez une méthode dans votre script, elle n'aura pas accès aux variables créées avec "def" dans le corps du script principal car elles ne sont pas dans la portée:

 x = 1
 def y = 2


public bar() {
    assert x == 1

    try {
        assert y == 2
    } catch (groovy.lang.MissingPropertyException e) {
        println "error caught"
    }
}

bar()

affiche "erreur interceptée"

La variable "y" n'est pas dans la portée de la fonction. "x" est dans la portée car groovy vérifiera les liaisons du script actuel pour la variable. Comme je l'ai dit plus tôt, il s'agit simplement d'un sucre syntaxique qui permet de dactylographier rapidement des scripts vides et sales (souvent une ligne).

Dans les gros scripts, il est recommandé de toujours utiliser le mot-clé "def" afin d'éviter les problèmes de portée étranges et de ne pas interférer avec des variables non souhaitées.

266
Ted Naleid

réponse de Ted est excellent pour les scripts; La réponse de Ben est la norme pour les classes.

Comme Ben le dit, considérez-le comme un "objet" - mais c'est beaucoup plus cool en ce sens que cela ne vous contraint pas aux méthodes Object. Cela a des conséquences intéressantes sur les importations.

par exemple. Dans cet extrait, je dois importer 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()

par exemple. Mais ici, je peux simplement "m'enfiler" tant que tout est sur le chemin de la classe

// 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()
35
Michael Easter

Selon ceci page , def remplace un nom de type et peut simplement être considéré comme un alias pour Object (ce qui signifie que vous ne vous souciez pas de sur le type).

29
Ben Hoffstein

En ce qui concerne ce script unique, il n'y a pas de différence pratique.

Toutefois, les variables définies à l'aide du mot clé "def" sont traitées comme des variables locales, c'est-à-dire locales pour ce script. Les variables sans "def" devant elles sont stockées dans une "liaison" lors de la première utilisation. Vous pouvez considérer la liaison comme une zone de stockage général pour les variables et les fermetures devant être disponibles "entre" les scripts.

Ainsi, si vous avez deux scripts et que vous les exécutez avec le même GroovyShell, le second script pourra obtenir toutes les variables définies dans le premier script sans "def".

12
Martin Stephan

La raison de "def" est de dire à groovy que vous avez l'intention de créer une variable ici. C'est important parce que vous ne voulez jamais créer une variable par accident.

C’est quelque peu acceptable dans les scripts (les scripts Groovy et Groovysh vous le permettent), mais dans le code de production, c’est l’un des plus grands maux que vous puissiez rencontrer. C’est pourquoi vous devez définir une variable avec def dans tout le code groovy actuel ( classe).

Voici un exemple de pourquoi c'est mauvais. Cela fonctionnera (sans rater l'assertion) si vous copiez le code suivant et le collez dans groovysh:

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

Ce type de problème peut prendre beaucoup de temps à trouver et à résoudre - Même si cela ne vous prenait qu'une seule fois dans votre vie, cela coûterait plus de temps que de déclarer explicitement les variables des milliers de fois au cours de votre carrière. Cela devient également clair à l'œil juste à l'endroit où il est déclaré, vous n'avez pas à deviner.

Dans les scripts/entrées sans importance de la console (comme la console groovy), c'est quelque peu acceptable car la portée du script est limitée. Je pense que la seule raison pour laquelle groovy vous permet de faire cela dans les scripts est de supporter les DSL comme Ruby le fait (un mauvais compromis si vous me le demandez, mais certaines personnes aiment les DSL))

8
Bill K

En fait, je ne pas pense que cela se comporterait de la même manière ...

les variables dans Groovy nécessitent toujours une déclaration, mais pas une déclaration TYPED, car le côté droit contient généralement suffisamment d'informations pour que Groovy puisse taper la variable.

Lorsque j'essaie d'utiliser une variable que je n'ai pas déclarée avec def ou un type, j'obtiens une erreur "Aucune propriété de ce type", car elle suppose que j'utilise un membre de la classe contenant le code.

5
billjamesdev