Groovy: qual è lo scopo di "def" in "def x = 0"?


180

Nel seguente pezzo di codice (tratto dalla pagina del Manuale di Semantica di Groovy ), perché aggiungere il prefisso all'assegnazione con la parola chiave def?

def x = 0
def y = 5

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

assert x == 5

La defparola chiave può essere rimossa e questo frammento produrrebbe gli stessi risultati. Quindi qual è l' effetto della parola chiave def?

Risposte:


278

È zucchero sintattico per gli script di base. L'omissione della parola chiave "def" inserisce la variabile nei collegamenti per lo script corrente e Groovy la tratta (principalmente) come una variabile con ambito globale:

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

L'uso della parola chiave def invece non inserisce la variabile nei collegamenti degli script:

def y = 2

assert y == 2

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

Stampe: "errore rilevato"

L'uso della parola chiave def in programmi più grandi è importante in quanto aiuta a definire l'ambito in cui è possibile trovare la variabile e può aiutare a preservare l'incapsulamento.

Se si definisce un metodo nel proprio script, non avrà accesso alle variabili create con "def" nel corpo dello script principale in quanto non rientrano nell'ambito:

 x = 1
 def y = 2


public bar() {
    assert x == 1

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

bar()

stampa "errore rilevato"

La variabile "y" non rientra nell'ambito della funzione. "x" è nell'ambito poiché groovy controllerà i binding dello script corrente per la variabile. Come ho detto prima, questo è semplicemente zucchero sintattico per rendere più veloci la digitazione di script veloci e sporchi (spesso una riga).

La buona pratica negli script più grandi è quella di utilizzare sempre la parola chiave "def" in modo da non incorrere in strani problemi di ambito o interferire con le variabili che non si intende.


36

La risposta di Ted è eccellente per gli script; La risposta di Ben è standard per le lezioni.

Come dice Ben, pensalo come "Oggetto" - ma è molto più interessante in quanto non ti costringe ai metodi Oggetto. Ciò ha implicazioni chiare per quanto riguarda le importazioni.

ad es. in questo frammento devo importare 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()

ad esempio, ma qui posso solo 'ala' finché tutto è sul sentiero di 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()

1
perché ti è stato permesso di new FileInputStream('Test.groovy').getChannel()escludere l'importazione?
Alexander Suraphel,

3
@AlexanderSuraphel "fintanto che tutto è sul sentiero di classe"
Hanno il

30

Secondo questa pagina , defè un sostituto per un nome di tipo e può essere semplicemente considerato un alias per Object(cioè significa che non ti interessa il tipo).


12

Per quanto riguarda questo singolo script, non vi è alcuna differenza pratica.

Tuttavia, le variabili definite utilizzando la parola chiave "def" sono trattate come variabili locali, ovvero locali a questo script. Le variabili senza la "def" davanti a loro sono memorizzate in un cosiddetto binding al primo utilizzo. Puoi considerare l'associazione come un'area di archiviazione generale per variabili e chiusure che devono essere disponibili "tra" gli script.

Quindi, se hai due script ed eseguili con lo stesso GroovyShell, il secondo script sarà in grado di ottenere tutte le variabili che sono state impostate nel primo script senza una "def".


8

Il motivo di "def" è dire a Groovy che si intende creare una variabile qui. È importante perché non vuoi mai creare una variabile per caso.

È abbastanza accettabile negli script (gli script Groovy e groovysh ti consentono di farlo), ma nel codice di produzione è uno dei mali più grandi che puoi incontrare, motivo per cui devi definire una variabile con def in tutto il codice groovy effettivo (qualsiasi cosa all'interno di un classe).

Ecco un esempio del perché è male. Questo verrà eseguito (senza fallire l'asserzione) se copi il seguente codice e lo incolli in groovysh:

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

Questo tipo di problema può richiedere molto tempo per trovare e risolvere - Anche se ti colpisse solo una volta nella vita, costerebbe comunque più tempo rispetto a dichiarare esplicitamente le variabili migliaia di volte durante la tua carriera. Inoltre diventa chiaro agli occhi proprio dove viene dichiarato, non devi indovinare.

In script non importanti / input di console (come la console groovy) è in qualche modo accettabile perché l'ambito dello script è limitato. Penso che l'unica ragione per cui Groovy ti consente di farlo negli script sia di supportare i DSL come fa Ruby (un brutto compromesso se me lo chiedi, ma alcune persone adorano i DSL)


5

In realtà, non penso che si comporterebbe lo stesso ...

le variabili in Groovy richiedono ancora una dichiarazione, ma non una dichiarazione TYPED, poiché il lato destro generalmente contiene informazioni sufficienti per Groovy per digitare la variabile.

Quando provo ad usare una variabile che non ho dichiarato con def o un tipo, ricevo un errore "Nessuna proprietà del genere", dato che presuppone che sto usando un membro della classe contenente il codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.