在下面的代码中,为什么Groovy似乎忽略了方法barMany中提供的closure参数的泛型类型声明:
import groovy.transform.CompileStatic @CompileStatic class Main { static main(args) { FooSub foo = new FooSub() BarSub bar = new BarSub() } } @CompileStatic class Foo<T> { void fooOne (T item) {} void fooMany(List<T> items) { items.each { T item -> fooOne(item) } // Compiles fine. } } @CompileStatic class FooSub extends Foo<Integer> {} @CompileStatic class Bar<T extends Bar<T>> { void barOne (T item) {} void barMany(List<T> items) { items.each { T item -> barOne(item) } // Error: // Cannot find matching method Bar#barOne(java.lang.Object) !!! items.each { T item -> barOne(item as T) } // Error: // Expected parameter of type java.lang.Object but got T !!! items.each { item -> barOne(item as T) } // Compiles fine - closure kNows about T } void barManyMore(List<T> items) { for (T item in items) { // Compiles fine. barOne(item) } } } @CompileStatic class BarSub extends Bar<BarSub> {}
更新:
Groovy版本:2.4.5 JVM:1.7.0_80供应商:Oracle Corporation操作系统:Linux
更新
所以我之前没有注意到这个奇怪的错误 – org.codehaus.groovy.control.MultipleCompilationErrorsException:启动失败 – 我将发布完整输出:
~/grov/tests$groovyc generics.groovy org.codehaus.groovy.control.MultipleCompilationErrorsException: startup Failed: generics.groovy: 27: Expected parameter of type java.lang.Object but got T @ line 27,column 19. items.each { T item -> barOne(item) } // Error: ^ generics.groovy: 27: [Static type checking] - Cannot find matching method Bar#barOne(java.lang.Object). Please check if the declared type is right and if the method exists. @ line 27,column 29. items.each { T item -> barOne(item) } // Error: ^ generics.groovy: 30: Expected parameter of type java.lang.Object but got T @ line 30,column 22. items.each { T item -> barOne(item as T) } // Error: ^ 3 errors ~/grov/tests$groovyc -v Groovy compiler version 2.4.5 copyright 2003-2015 The Apache Software Foundation. http://groovy-lang.org/
更新
完整性的一些更多变通方法:
这些变通办法似乎有效:
Closure c = { T item -> barOne(item) }; items.each c // See comments by @tim_yates items.each ( { T item -> barOne(item) } as Closure) // Casting to closure works too!
当类型是基于泛型T的类时,同样的问题也适用:
@CompileStatic class Baz<T extends Baz<T>> { List<T> getList() { return [new T(),new T()] } } @CompileStatic class BazClient { void useBaz(Baz baz) { // baz.getList().each {Baz it -> println it} // Error Closure c = {Baz it -> println it}; baz.getList().each c // works baz.getList().each ({Baz it -> println it} as Closure) // works } }
解决方法
这是与泛型相关的
bugs之一,已在Groovy 2.4.6中修复.