0

このスニペットを見てください:

def line = "asdf"

String foo() {
  try {
     //line = "qwer"
     return line
  } finally {
     line = "zxcv"
  }
}

println line
println foo()
println line

.NETのバックグラウンドから来ると、印刷行が生成されると予想されます

asdf
asdf
zxcv

ただし、groovyでは、生成されます

asdf
zxcv
asdf

これはいくつかの点で私を困惑させます。

1) の値を印刷すると、なぜfoo()生成されるのzxcvですか? linereturn ステートメントが評価されて return を試行することを期待しますが、戻り値に影響を与えないasdfset 行を返す前に。asdf

2) 2 番目の出力はであるため、行IS が実行されるzxcvことを受け入れる必要があります。では、なぜ3 番目の出力に対してline = "zxcv"BACK が設定されているのでしょうか。asdf

3) 行のコメントを外すと、line = "qwer"次のような出力が生成されます。

asdf
qwer
asdf

どちらのモデルとも矛盾していると思います。奇妙なスコーピング動作のように見えますが、ルールがここにあるのかわかりません。

Groovy 2.2.2 の使用

編集:ああ!これをgroovyコンソールから実行しています。これをクラスでラップして実行すると、プログラムは期待される出力を生成するようです。

class MyClass {
    def line = "asdf"

    String foo() {
      try {
         //line = "qwer"
         return line
      } finally {
         line = "zxcv"
      }
    }

    def printStuff() {    
      println line
      println foo()
      println line
    }
}

new MyClass().printStuff()

生産する

asdf
asdf
zxcv

また、[スクリプト] -> [スクリプト コンテキストのクリア] メニュー オプションも発見しました。スクリプト コンテキストをクリアした直後に元のスニペットを実行すると、コンソールは次の例外をスローします。

asdf
Exception thrown

groovy.lang.MissingPropertyException: No such property: line for class: ConsoleScript53

    at ConsoleScript53.foo(ConsoleScript53:6)

    at ConsoleScript53.run(ConsoleScript53:13)

後続の実行で誤った出力が生成される

asdf
zxcv
asdf

この新しい情報を武器に、GroovyConsole には奇妙な点があり、そのコンテキストに持ち上げられ、上部で宣言されてlineいる代わりにそれを返しているようです。lineか何か。言語の問題ではなく、ツールの問題であることを知っていると、私が本当に楽しみ始めたばかりのこの言語から悲鳴を上げたくなくなりました。

4

2 に答える 2

3

http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22で状況を少し説明します。

基本的defに、.Net の結果を得るには、最初の行の を削除する必要があります。

しかし、ここでネイサンと一緒に考えなければなりません。あなたのプログラムは通常、あなたが言った出力を生成しません。これは、リンクされたページを読んだことがあれば、lineinfoo()がバインディングを参照しているのに対し、lineoutsidefoo()はバインディングとは独立したローカル変数であることがわかるからです。したがって、期待される結果はMissingPropertyException、実行時に forを取得することreturn lineです。それはline、最初にそこに書き込む前にバインディングに存在しないためです。

見た出力を生成するには、実際に追加する必要があります

line = "zxcv"

の前にdef。これによりline、バインディングに存在することが保証されます。の後に追加するとdef、ローカル変数が書き込まれ、binding.line代わりに使用する必要があります。より簡単にするために、ここで完全なプログラムをもう一度示します。

line = "zxcv"
def line = "asdf"

String foo() {
  try {
     //line = "qwer"
     return line
  } finally {
     line = "zxcv"
  }
}

println line
println foo()
println line

したがって、この修正されたプログラムがあれば、あなたの質問に答えることができます。

  1. の値を出力すると、関数に入ったときの line の値がfoo()生成されるためです。zxcvたとえば、最初の行を使用するように変更する123123、代わりに が得られますzxcv
  2. line = "zxcv"は実際に実行され、バインディングに格納されているものを変更します。ただし、メソッドが返すものは変更されないため、それfoobarを行に割り当てるように変更しても同じ結果が得られます。そして、3 つ目printlnはバインディングの代わりにローカル変数から読み取っているため、 の可視効果の欠如foo()についても説明されています。
  3. 元のプログラムで のコメントを外すline = "qwer"と、バインディングに何かがあることが保証されるため、MissingPropertyException. ただし、ブロックが実行されるfoo()前にバインディングにあったものを返すため、元に戻ります。finallyqwer
于 2014-05-22T14:53:12.487 に答える