我正在阅读https://groovy-lang.org/closures.html#this中的 Groovy 闭包文档。对 GString 行为有疑问。
- GString 中的闭包
该文件提到了以下内容:
采取以下代码:
def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'
代码的行为与您预期的一样,但是如果您添加以下内容会发生什么:
x = 2
assert gs == 'x = 2'
你会看到断言失败了!有两个原因:
GString 仅懒惰地评估值的 toString 表示
GString 中的语法 ${x} 不代表闭包,而是 $x 的表达式,在创建 GString 时进行评估。
在我们的示例中,GString 是使用引用 x 的表达式创建的。当 GString 被创建时,x 的值为 1,因此 GString 被创建为值为 1。当断言被触发时,GString 被求值并使用 toString 将 1 转换为 String。当我们将 x 更改为 2 时,我们确实更改了 x 的值,但它是一个不同的对象,GString 仍然引用旧的。
只有当 GString 引用的值发生变化时,GString 才会更改其 toString 表示。如果引用发生变化,什么都不会发生。
我的问题是关于上面引用的解释,在示例代码中,1 显然是一个值,而不是引用类型,那么如果这个陈述是真的,它应该在 GString 中更新为 2 对吗?
下面列出的下一个示例我也觉得有点困惑(最后一部分)为什么如果我们改变 Sam 以将他的名字更改为 Lucy,这次 GString 被正确地改变了?我期待它不会变异??为什么两个示例中的行为如此不同?
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 正确变异了?在之前的评论中,它刚刚提到
字符串仍然计算为 Sam,因为它是创建 GString 时 p 的值,创建 String 时 p 的值是 'Sam'
因此我认为它不应该在这里改变?感谢您的帮助。