Groovyclosure-on-collection-methods 不一致的类型转换

标签 groovy spock

Groovy 中有一些奇怪的行为。看看下面的两个例子:

def list = [[BigDecimal.ONE]]
list.each {
    println it.class
}

打印:

class java.util.ArrayList




def list = [[BigDecimal.ONE]]
list.each { BigDecimal it ->
    println it.class
}

打印:

class java.math.BigDecimal



示例中唯一的区别是第二个具有指定闭包的参数类型。但这并不能解释内部 List 的原因和方式正在转换为 BigDecimal .我宁愿期待 ClassCastException .此外,这种行为是不一致的,好像内部列表中有更多元素它失败了 MissingMethodException .

我们发现这种神奇的类型转换发生在 ClosureMetaClass (行:256)

这是设计的行为还是错误?

编辑:
我在尝试使用 Spock stub 方法时遇到了上述问题。该方法采用Collection作为参数。考虑另一个例子:
def 'stub a method with collection as argument'() {
    given:
    def input = [1, 2, 3]
    def capturedArgument
    List listStub = Stub()
    listStub.addAll(input) >> {
        capturedArgument = it
    }

    when:
    listStub.addAll(input)

    then:
    input.class == capturedArgument.class
}

它失败了:
Condition not satisfied:

input.class == capturedArgument.class
|     |     |  |                |
|     |     |  [[1, 2, 3]]      class java.util.Arrays$ArrayList
|     |     false
|     class java.util.ArrayList
[1, 2, 3]

问题在于参数 it来自 List嵌入另一个 List进入方法 stub 闭包。怎么回事?

克服这个问题的唯一方法是使用 的 stub 方法。与输入类型 完全相同的参数类型像
listStub.addAll(input) >> { ArrayList it ->

...然后测试通过。这是一个真正的禁忌,因为我需要使用接口(interface)作为 stub 参数类型,而不是特定的实现。当它被宣布为
listStub.addAll(input) >> { List it ->

或者
listStub.addAll(input) >> { Collection it ->

...它以与没有类型相同的方式失败,因为输入列表被嵌入到另一个列表中。

这里是 live example如果你喜欢运行和玩耍

最佳答案

groovy 解构提供给闭包的项目(最好的例子是每个在 Map 上,其中传递了键和值)。所以在一致使用上是一致的:

[[BigDecimal.ONE],[BigDecimal.ONE]].each{ BigDecimal it -> println it } 
//=> 1
//=> 1
[[BigDecimal.ONE, BigDecimal.ONE]].each{ a, b -> println "$a and $b" }
//=> 1 and 1

关于Groovyclosure-on-collection-methods 不一致的类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27780377/

相关文章:

jenkinsfile 无法识别@Grab

java - 阅读器中的多个标记

arrays - 自定义排序 Groovy JSONArray - 首先自定义值,然后按字母顺序

java - 在 Grails 应用程序中管理 Java 依赖项?

java - Spock - 模拟私有(private)字段

java - 简单 Spock 测试中的日志记录级别没有变化

gradle - 将maven-surefire-plugin转换为gradle以进行Geb/Spock并行测试

spring - 在 Groovy/Gradle 构建中使用 JPA 复合键时,Spock 测试失败

java - 防止 JSPX 创建自闭合标记 (<div></div> != <div/>)

java - Spock:在 "where"子句表中使用 Mock?