https://groovy-lang.org/closures.html#thisで Groovy クロージャーのドキュメントを読んでいます。GString の動作に関して質問があります。
- GStrings のクロージャ
ドキュメントには次のように記載されていました。
次のコードを使用します。
def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'
コードは期待どおりに動作しますが、次を追加するとどうなりますか。
x = 2
assert gs == 'x = 2'
アサートが失敗することがわかります。これには 2 つの理由があります。
GString は、値の toString 表現のみを遅延評価します
GString の構文 ${x} はクロージャーを表すのではなく、GString の作成時に評価される $x への式を表します。
この例では、GString は x を参照する式で作成されます。GString が作成されるとき、x の値は 1 であるため、値 1 で GString が作成されます。アサートがトリガーされると、GString が評価され、toString を使用して 1 が String に変換されます。x を 2 に変更すると、x の値が変更されましたが、これは別のオブジェクトであり、GString はまだ古いオブジェクトを参照しています。
GString は、参照する値が変化している場合にのみ、その toString 表現を変更します。参照が変更されても、何も起こりません。
私の質問は、上記の説明に関するものです。コード例では、1 は明らかに値であり、参照型ではありません。このステートメントが true の場合、GString で 2 に更新する必要があります。
以下にリストされている次の例も、少し混乱しているように感じます (最後の部分)。Sam を変更して名前を Lucy に変更すると、今度は GString が正しく変更されるのはなぜですか?? 私はそれが変異しないことを期待しています?? 2 つの例で動作が大きく異なるのはなぜですか?
class Person {
String name
String toString() { name }
}
def sam = new Person(name:'Sam')
def lucy = new Person(name:'Lucy')
def p = sam
def gs = "Name: ${p}"
assert gs == 'Name: Sam'
p = Lucy. //if we change p to Lucy
assert gs == 'Name: Sam' // the string still evaluates to Sam because it was the value of p when the GString was created
/* I would expect below to be 'Name: Sam' as well
* if previous example is true. According to the
* explanation mentioned previously.
*/
sam.name = 'Lucy' // so if we mutate Sam to change his name to Lucy
assert gs == 'Name: Lucy' // this time the GString is correctly mutated
コメントに「今回は GString が正しく変更された」と記載されているのはなぜですか? 以前のコメントでは、言及したばかりです
GString が作成されたときは p の値であったため、文字列は引き続き Sam に評価されます。文字列が作成されたときの p の値は「Sam」です。
したがって、ここで変更すべきではないと思いますか?? 親切な助けをありがとう。