Groovyのクロージャからスクリプト変数を変更する

SiKing

関数のクロージャ内からスクリプト変数を変更しようとしています。問題はこれに要約することができます:

@groovy.transform.Field int myField = 0

incrementField()
assert myField == 1

def incrementField() {
    1.times { myField++ }
}

この問題はクロージャーデリゲートと関係があると思いますが、ドキュメントに頭を悩ませることはできません。

Szymon Stepniak

この動作は、groovy.lang.Scriptクラスと、次のメソッドをオーバーライドするという事実が原因で発生します。

例で示したクロージャはdelegate、スクリプトオブジェクトに設定されたものを使用します。そのため、スクリプトで定義されたフィールドにアクセスまたは変更しようとすると、オーバーライドされた両方のメソッドが実行されます。

次に、例が終了したときに何が起こるかを見てみましょう。

{ myField++ }

まず、getProperty("myField")このプロパティに関連付けられた値を返すために呼び出されます。このメソッドは次のように実装されます。

public Object getProperty(String property) {
    try {
        return binding.getVariable(property);
    } catch (MissingPropertyException e) {
        return super.getProperty(property);
    }
}

ソース:https//github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L54

bindingオブジェクトの先頭には、クロージャーのargs配列という1つの変数しか含まれていませんbinding.getVariable(property)メソッドの実装を見ると、次のことがわかります。

public Object getVariable(String name) {
    if (variables == null)
        throw new MissingPropertyException(name, this.getClass());

    Object result = variables.get(name);

    if (result == null && !variables.containsKey(name)) {
        throw new MissingPropertyException(name, this.getClass());
    }

    return result;
}

ソース:https//github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Binding.java#L56

この場合MissingPropertyExceptionはスローされているため、Script.getProperty(property)メソッドはmyFieldGroovyスクリプトで定義されたフィールドの値を返します- 0次に、Groovyはこの値を1ずつインクリメントし、この新しい値をフィールドに設定しようとしますmyFieldこの場合Script.setProperty(property, value)、次のように呼び出されます。

public void setProperty(String property, Object newValue) {
    if ("binding".equals(property))
        setBinding((Binding) newValue);
    else if("metaClass".equals(property))
        setMetaClass((MetaClass)newValue);
    else
        binding.setVariable(property, newValue);
}

ソース:https//github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L62

ご覧のとおり、bindingsオブジェクトを使用してこの新しい値を設定します。表示binding.variablesすると、この内部マップに2つのエントリが含まれていることがわかります:args -> [:]myField -> 1スクリプトのアサーションが常に失敗する理由を説明します。定義したクロージャーの本体は、myFieldスクリプトクラスのフィールドに到達することはありません

回避策

ScriptクラスがsetProperty(property, value)メソッドをオーバーライドするという事実に満足できない場合は、スクリプトでいつでも手動でオーバーライドして、と同じ実装を使用できますGroovyObjectSupport.setProperty(property, value)以下のメソッドをGroovyスクリプトに追加するだけです。

@Override
void setProperty(String property, Object newValue) {
    getMetaClass().setProperty(this, property, newValue)
}

これで、で定義されたクロージャincrementFieldは、bindingsオブジェクトではなくクラスフィールドに新しい値を設定します。もちろん、それはいくつかの奇妙な副作用を引き起こす可能性があります、あなたはそれを知っている必要があります。お役に立てば幸いです。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

スクリプトコンソールからgroovyスクリプトを使用して、複数のジョブのgitSCMを変更します

分類Dev

別のスクリプトからjs変数を変更する

分類Dev

MySQLストアドプロシージャは秒クエリから変数値を返しますか?

分類Dev

リスナーをGroovyのクロージャに変換する

分類Dev

期待スクリプトの変数からキャリッジリターン(\ r)を削除します

分類Dev

ネストされたクロージャーからローカル変数を変更するにはどうすればよいですか?

分類Dev

JavaScriptクロージャが親のスコープから変数を継承できるようにする

分類Dev

jenkinsジョブのsvnurlを変更するGroovyスクリプト

分類Dev

複数のプルリクエストとしてフォークから変更をプッシュする

分類Dev

インストールディレクトリを通知するUninstall()プロシージャの変数にアクセスすることは可能ですか?

分類Dev

クエリのOracleストアドプロシージャでグローバル変数を使用する方法

分類Dev

クロージャ内のグローバルスコープから変数にアクセスする

分類Dev

ストアドプロシージャのオープンクエリに変数を追加する方法

分類Dev

プロジェクトを変更せずに、JenkinsのマルチモジュールプロジェクトでSonarQubeスキャンからディレクトリを除外する

分類Dev

Javascriptでクロージャ変数のリストを取得する

分類Dev

JenkinsのGroovyスクリプトから環境変数を設定します

分類Dev

JenkinsのGroovyスクリプトから環境変数を設定します

分類Dev

別のスクリプトからIntを変更する

分類Dev

UWPプロジェクトのターゲットバージョンを1803から1809に変更すると、NavigationViewのアクリルテクスチャが無効になります-なぜですか?

分類Dev

ローカルマシン(Rstudio)のgithubからフォークされたプロジェクトのリモートリポジトリを変更する

分類Dev

複数の行を挿入しながら変数をインクリメントするストアドプロシージャ

分類Dev

C ++ 14の標準要件をPOCOベースのプロジェクトからC ++ 17に変更する方法

分類Dev

クエリ結果をMySqlストアドプロシージャの変数に格納する方法

分類Dev

同じクラスのクロージャから変数を変更することはできません[swift3.0]

分類Dev

ムービークリップ内からグローバル変数の値を変更する

分類Dev

リモートssh接続からgroovyスクリプトの他のステージに変数を渡す方法

分類Dev

シェルスクリプトから環境変数をロードする

分類Dev

変数名の変更ケースからストップ・ジャクソン

分類Dev

groovyスクリプトを使用してSoapUIのテストケースからスクリプトログをキャプチャする

Related 関連記事

  1. 1

    スクリプトコンソールからgroovyスクリプトを使用して、複数のジョブのgitSCMを変更します

  2. 2

    別のスクリプトからjs変数を変更する

  3. 3

    MySQLストアドプロシージャは秒クエリから変数値を返しますか?

  4. 4

    リスナーをGroovyのクロージャに変換する

  5. 5

    期待スクリプトの変数からキャリッジリターン(\ r)を削除します

  6. 6

    ネストされたクロージャーからローカル変数を変更するにはどうすればよいですか?

  7. 7

    JavaScriptクロージャが親のスコープから変数を継承できるようにする

  8. 8

    jenkinsジョブのsvnurlを変更するGroovyスクリプト

  9. 9

    複数のプルリクエストとしてフォークから変更をプッシュする

  10. 10

    インストールディレクトリを通知するUninstall()プロシージャの変数にアクセスすることは可能ですか?

  11. 11

    クエリのOracleストアドプロシージャでグローバル変数を使用する方法

  12. 12

    クロージャ内のグローバルスコープから変数にアクセスする

  13. 13

    ストアドプロシージャのオープンクエリに変数を追加する方法

  14. 14

    プロジェクトを変更せずに、JenkinsのマルチモジュールプロジェクトでSonarQubeスキャンからディレクトリを除外する

  15. 15

    Javascriptでクロージャ変数のリストを取得する

  16. 16

    JenkinsのGroovyスクリプトから環境変数を設定します

  17. 17

    JenkinsのGroovyスクリプトから環境変数を設定します

  18. 18

    別のスクリプトからIntを変更する

  19. 19

    UWPプロジェクトのターゲットバージョンを1803から1809に変更すると、NavigationViewのアクリルテクスチャが無効になります-なぜですか?

  20. 20

    ローカルマシン(Rstudio)のgithubからフォークされたプロジェクトのリモートリポジトリを変更する

  21. 21

    複数の行を挿入しながら変数をインクリメントするストアドプロシージャ

  22. 22

    C ++ 14の標準要件をPOCOベースのプロジェクトからC ++ 17に変更する方法

  23. 23

    クエリ結果をMySqlストアドプロシージャの変数に格納する方法

  24. 24

    同じクラスのクロージャから変数を変更することはできません[swift3.0]

  25. 25

    ムービークリップ内からグローバル変数の値を変更する

  26. 26

    リモートssh接続からgroovyスクリプトの他のステージに変数を渡す方法

  27. 27

    シェルスクリプトから環境変数をロードする

  28. 28

    変数名の変更ケースからストップ・ジャクソン

  29. 29

    groovyスクリプトを使用してSoapUIのテストケースからスクリプトログをキャプチャする

ホットタグ

アーカイブ