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


180

次のコード(Groovyセマンティクスのマニュアルページから抜粋)では、割り当ての前にキーワードを付けるのはなぜdefですか。

def x = 0
def y = 5

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

assert x == 5

defキーワードを除去することができ、このスニペットは、同じ結果を生成します。では、キーワードの効果は何defですか?

回答:


278

基本的なスクリプトの構文糖です。"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が変数の現在のスクリプトのバインディングをチェックするためです。先に述べたように、これは単純な構文糖であり、迅速かつダーティーなスクリプトをすばやくタイプアウトできます(多くの場合、1つのライナー)。

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


36

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

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

たとえば、このスニペットでは、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()

1
なぜnew FileInputStream('Test.groovy').getChannel()輸入を禁じられたのですか?
Alexander Suraphel 2013年

3
@AlexanderSuraphel「すべてがクラスパス上にある限り」
Hanno

30

このページによれば、defはタイプ名の代わりであり、単にのエイリアスと考えることができObjectます(つまり、タイプを気にしないことを意味します)。


12

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

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

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


8

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

スクリプト(Groovyスクリプトとgroovyshを使用すると許可されます)では多少許容できますが、実稼働コードでは遭遇する可能性のある最大の悪の1つであるため、実際のすべてのGroovyコード(変数内のすべてのもの)でdefを使用して変数を定義する必要がありますクラス)。

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

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

この種の問題は、発見して修正するのに長い時間がかかる可能性があります。たとえそれが人生で一度だけあなたに噛み付いたとしても、キャリア全体で変数を何千回も明示的に宣言するよりもさらに多くの時間がかかります。また、宣言されている場所がすぐにわかるので、推測する必要もありません。

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


5

実際、同じように動作すると思いません ...

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

defまたはtypeで宣言していない変数を使用しようとすると、コードを含むクラスのメンバーを使用していると見なされるため、「そのようなプロパティはありません」というエラーが表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.