Groovy 陷阱:字符串插值并不总是执行,例如在“<list>.contains()”中

Groovy Gotcha: String interpolation does not always execute, e.g. in `<list>.contains()`

答案:它与 GString 类型和“惰性求值”有关。

请参阅 http://docs.groovy-lang.org/latest/html/documentation/index.html#_string_interpolation 了解正式文档。

请参阅 https://blog.mrhaki.com/2009/08/groovy-goodness-string-strings-strings.html 了解某人对此的评论。

正如评论者所说,下面代码中的可靠解决方案是使用 String targ = "${TARGET_DATA}"

在创建时显式地转换它

我看到表面上看起来像是延迟的字符串插值或 Groovy 中的东西。我已经找到了满足我即时需求的解决方法,但这种行为是一个真正的问题,并且是严重错误的潜在来源...

我强烈怀疑这是因为 Groovy 是 Java 的一种元语言,而且一些对象没有使用通常的字符串匹配例程。

这是在我们尝试对 Jenkins 中的某些参数使用字符串插值并根据预先批准的值列表对其进行检查时发现的 - 因此出现了下面的示例。

考虑这段代码:

TARGET_DATA= "hello"
data = ["hello"]
targ = "${TARGET_DATA}"

// Case 1: Check for basic interpolated string

if( data.contains(targ) ) {
  println "Contained interpolated string"
} else {
  println "Interpolation failed"
}

// Case 2: Check to see if using something that actively forces its interpolation changes the variable

println "interpolating targ = ${targ}"

if( data.contains(targ) ) {
  println "Contained re-interpolated string"
} else {
  println "re-Interpolation failed"
}

// Case 3: Use direct variable assignment

targ = TARGET_DATA

if( data.contains(targ) ) {
  println "Contained assigned variable"
} else {
  println "Assignment failed"
}

它的输出是这样的:

Interpolation failed
interpolating targ = message: hello
re-Interpolation failed
Contained assigned variable

这表明:

我的猜测是targ字面上包含一个以美元符号、花括号和变量名等开头的字符串。这在某些条件下解析,就像使用 println 一样,但不是在 <list>.contains() 的情况下,它只是按原样获取未插值的变量,并且在检查期间不知道如何对其进行插值。

使用 targ = new String("${TARGET_DATA}") 确实 主动插入字符串,但是,因为对函数的调用以某种方式注册为活动。

但是这个代码确实正确插值:

TARGET_DATA= "hello"
targ = "${TARGET_DATA}"

def eq(var1) { return var1 == "hello" }

basic_check = eq(targ)

println "${basic_check}" // resolves as true

这意味着在某些时候,字符串被插入 - 可能 == 操作已被 Groovy 重新实现以始终调用 String 的相等函数:

这样,Groovy 重新实现了 String 对象 - 及其相等性检查 - 但 <list>.contains() 函数不使用该比较器(或者在脚本解释,由于在 Java 标准库中编译代码)因此无法触发插值替换...

有人可以在这里阐明一下吗?

targ 是 Gstring 类型,而不是 java 字符串。 GString 保留有关如何从内插形式构建自身的信息。

因为 targ 不是字符串,所以它永远不会通过 List.contains 要求的相等性检查,其中列表包含字符串。