Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
收集方法上的Groovy闭包不一致的类型转换_Groovy_Spock - Fatal编程技术网

收集方法上的Groovy闭包不一致的类型转换

收集方法上的Groovy闭包不一致的类型转换,groovy,spock,Groovy,Spock,Groovy中存在奇怪的行为。请看下面的两个示例: def list = [[BigDecimal.ONE]] list.each { println it.class } 印刷品: 类java.util.ArrayList 及 印刷品: 类java.math.BigDecimal 示例中唯一的区别是,第二个示例具有指定闭包的参数类型。但这并不能解释为什么以及如何将内部列表转换为BigDecimal。我宁愿期望ClassCastException。此外,这种行为是不一致的,好像内部列表

Groovy中存在奇怪的行为。请看下面的两个示例:

def list = [[BigDecimal.ONE]]
list.each {
    println it.class
}
印刷品:

类java.util.ArrayList

印刷品:

类java.math.BigDecimal

示例中唯一的区别是,第二个示例具有指定闭包的参数类型。但这并不能解释为什么以及如何将内部
列表
转换为
BigDecimal
。我宁愿期望
ClassCastException
。此外,这种行为是不一致的,好像内部列表中有更多的元素,它会失败,导致
MissingMethodException

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

这是一个设计的行为还是一个bug

编辑: 我在尝试使用Spock存根方法时遇到了上述问题。该方法将
集合
作为参数。考虑另一个例子:

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]
问题是参数
作为
List
嵌入到另一个
List
方法存根闭包中。WTF

克服这一问题的唯一方法是使用与输入类型完全相同的参数类型的stubing方法

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

listStub.addAll(input) >> { List it ->

…由于输入列表嵌入到另一个列表中,因此与不使用类型时失败的方式相同


如果您想运行和使用它,下面是groovy解构提供给闭包的项(最好的例子是
映射中的每个项,其中传递键和值)。因此,它在一致的使用上是一致的:

[[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

谢谢你的解释。我可以通过
Map
了解这种行为的原因,而且我经常使用它。但是,使用
集合
可能会导致意外的应用程序行为。无论如何,你能在我的原始问题的“编辑”部分下看一看并解释这个谜团吗?很抱歉,我无法帮助解决斯波克问题,而且这甚至会产生一个新问题(例如,彼得有机会提供完整的答案)谢谢,我不确定这是不是同一个问题。事实上并不完全相同,但它们是相关的。我正考虑把它作为一个新问题来问,也许我应该问。capturedArguments的类型是:
java.util.Arrays$ArrayList
,因为
DefaultGroovyMethods.java
公共静态布尔addAll(集合self,T[]项){return self.addAll(Arrays.asList(项));}
。一切正常。如果显式指定参数,它将自动转换,并且不会引发异常。请参阅:在Spock模拟响应中,
it
或单个非类型化闭包参数将包含方法的参数列表。如果改用类型化闭包参数,Spock将尝试根据Groovy语义进行结构分解。看,谢谢你,彼得。我现在明白了为什么我的输入列表被嵌入到另一个非类型化Spock模拟响应参数的列表中。但为什么即使参数是类型化的,但使用父类或接口,也会发生同样的情况呢?当然,我会再看一遍文档,但如果你能多说几句话,那就太棒了。下面是我想问的一个例子,这种方法需要多次删除同一个方法,比如:LinkedList、ArrayList、Set等等。。。这看起来不太好,即使CodeNarc抱怨ImplementationAsTypeDestructuring将(仅)在闭包参数无法按闭包声明的参数类型传递时启动。(与我之前所说的相反,所有这些都在Groovy的控制之下,因此遵循标准Groovy语义。Spock只使用一个
List
类型的参数调用闭包,表示存根调用的参数列表。)换句话说,当使用类型为
Iterable
Collection
List
的单个参数存根一个方法时,您必须手动分解结构(
{args->args[0]}
>{it[0]}
)。^^^最后一句话最好放在文档中。
listStub.addAll(input) >> { Collection it ->
[[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