次のコード片 ( Groovy Semantics のマニュアル ページから抜粋) では、割り当ての前にキーワード を付けたのはなぜdef
でしょうか?
def x = 0
def y = 5
while ( y-- > 0 ) {
println "" + x + " " + y
x++
}
assert x == 5
キーワードは削除でき、このdef
スニペットは同じ結果を生成します。では、キーワードの効果は何def
ですか?
次のコード片 ( Groovy Semantics のマニュアル ページから抜粋) では、割り当ての前にキーワード を付けたのはなぜdef
でしょうか?
def x = 0
def y = 5
while ( y-- > 0 ) {
println "" + x + " " + y
x++
}
assert x == 5
キーワードは削除でき、このdef
スニペットは同じ結果を生成します。では、キーワードの効果は何def
ですか?
これは、基本的なスクリプトのシンタックス シュガーです。「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" キーワードを使用することをお勧めします。これにより、奇妙なスコープの問題に遭遇したり、意図しない変数に干渉したりしなくなります。
テッドの答えはスクリプトに最適です。ベンの答えはクラスの標準です。
Ben が言うように、これを「オブジェクト」と考えてください。ただし、オブジェクト メソッドに制約されないという点で、はるかに優れています。これは、輸入に関してきちんとした意味を持ちます。
たとえば、このスニペットでは、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()
このページによると、def
は型名の代わりであり、単純に のエイリアスと考えることができObject
ます (つまり、型を気にしないことを意味します)。
この単一のスクリプトに関する限り、実質的な違いはありません。
ただし、キーワード「def」を使用して定義された変数は、ローカル変数、つまりこの 1 つのスクリプトに対してローカルな変数として扱われます。前に「def」がない変数は、最初の使用時にいわゆるバインディングに格納されます。バインディングは、スクリプトの「間」で使用可能にする必要がある変数とクロージャーの一般的なストレージ領域と考えることができます。
したがって、2 つのスクリプトがあり、それらを同じ GroovyShell で実行すると、2 番目のスクリプトは最初のスクリプトで設定されたすべての変数を「def」なしで取得できます。
「def」の理由は、ここで変数を作成するつもりであることを groovy に伝えるためです。誤って変数を作成したくないため、これは重要です。
スクリプトでは多少許容されますが (Groovy スクリプトと groovysh ではそれが可能です)、実稼働コードでは遭遇する可能性のある最大の弊害の 1 つであり、すべての実際の groovy コード (クラス)。
ダメな理由の一例です。次のコードをコピーして groovysh に貼り付けると、(アサートに失敗することなく) これが実行されます。
bill = 7
bi1l = bill + 3
assert bill == 7
この種の問題は、発見して修正するのに多くの時間がかかる可能性があります。人生で一度だけ噛まれたとしても、キャリアを通じて変数を何千回も明示的に宣言するよりも時間がかかります。また、どこで宣言されているかが明確になるので、推測する必要はありません。
重要でないスクリプト/コンソール入力 (Groovy コンソールなど) では、スクリプトのスコープが制限されているため、ある程度許容されます。groovy がスクリプトでこれを行うことを許可する唯一の理由は、Ruby が行うように DSL をサポートするためだと思います (私に言わせれば悪いトレードオフですが、一部の人々は DSL を愛しています)。
実際、私はそれが同じように振る舞うとは思わ ない...
Groovy の変数には、通常、Groovy が変数を型指定するのに十分な情報が右側に含まれているため、TYPED 宣言だけでなく、宣言も必要です。
def または型で宣言していない変数を使用しようとすると、コードを含むクラスのメンバーを使用していると見なされるため、「そのようなプロパティはありません」というエラーが表示されます。