web-dev-qa-db-ja.com

Groovy:「def x = 0」の「def」の目的は何ですか?

次のコード( Groovy Semantics Manualページ から取得)で、キーワードdefを割り当ての前に付けるのはなぜですか?

def x = 0
def y = 5

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

assert x == 5

defキーワードは削除でき、このスニペットは同じ結果を生成します。それでは、キーワードdefeffectは何ですか?

172
Leonel

基本的なスクリプトの構文糖衣です。 「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」変数は、関数内のスコープ内にありません。 groovyは変数の現在のスクリプトのバインディングをチェックするため、「x」はスコープ内にあります。前に言ったように、これは単純な構文シュガーであり、素早くて汚いスクリプトをすばやく入力できます(多くの場合、1つのライナー)。

大きなスクリプトでは、常に "def"キーワードを使用して、奇妙なスコープの問題に遭遇したり、意図しない変数に干渉したりしないようにすることをお勧めします。

266
Ted Naleid

テッドの答え はスクリプトに最適です。 ベンの答え はクラスの標準です。

ベンが言うように、それを「オブジェクト」と考えてください。しかし、オブジェクトメソッドに制約されないという点で、はるかにクールです。これは、輸入に関してきちんとした意味を持ちます。

例えばこのスニペットでは、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()
35
Michael Easter

これによると pagedefは型名の置換であり、単にObjectのエイリアスと考えることができます(つまり、気にしないことを意味します)タイプ)。

29
Ben Hoffstein

この単一のスクリプトに関する限り、実際的な違いはありません。

ただし、キーワード「def」を使用して定義された変数は、ローカル変数、つまり、この1つのスクリプトに対してローカルとして扱われます。変数の前に「def」がない変数は、最初の使用時にいわゆるバインディングに保存されます。バインディングは、「間」スクリプトで使用可能にする必要がある変数とクロージャーの一般的なストレージ領域と考えることができます。

したがって、2つのスクリプトがあり、それらを同じGroovyShellで実行すると、2番目のスクリプトは、「def」なしで最初のスクリプトで設定されたすべての変数を取得できます。

12
Martin Stephan

「def」の理由は、ここで変数を作成するつもりであることをgroovyに伝えるためです。誤って変数を作成したくないので重要です。

スクリプトでは多少受け入れられますが(Groovyスクリプトとgroovyshで許可されます)、実稼働コードでは遭遇する可能性がある最大の悪の1つであるため、すべての実際のgroovyコード(defクラス)。

これが悪い理由の例です。次のコードをコピーしてgroovyshに貼り付けると、これは(アサートに失敗することなく)実行されます。

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

この種の問題は、見つけて修正するのに時間がかかる場合があります。たとえ人生で一度だけ噛みついたとしても、キャリアを通じて変数を何千回も明示的に宣言するよりも時間がかかります。また、それが宣言されている場所で目に見えるようになります。推測する必要はありません。

重要でないスクリプト/コンソール入力(groovyコンソールなど)では、スクリプトのスコープが制限されているため、ある程度許容できます。 groovyがスクリプトでこれを行うことを許可する唯一の理由は、Rubyが行うようにDSLをサポートすることだと思います(私に尋ねると悪いトレードオフですが、一部の人々はDSLを愛しています)

8
Bill K

実際、私はしない同じように振る舞うと思います...

groovyの変数には、TYPED宣言ではなく、宣言が必要です。これは、通常、右側にGroovyが変数を入力するのに十分な情報が含まれているためです。

Defまたはtypeで宣言していない変数を使用しようとすると、「No such property」というエラーが表示されます。これは、コードを含むクラスのメンバーを使用していると想定しているためです。

5
billjamesdev