尝试使用泛型类但遇到以下问题,即:
类型不匹配:推断类型为
ChildClass
,但预计为SuperClass<SuperType>
open class SuperClass<T> where T: SuperType {
fun modifySomething(input: T): T {
input.someValue.inc()
return input
}
}
open class SuperType {
val someValue: Int = 0
}
class ChildClass : SuperClass<ChildType>()
class ChildType: SuperType() {
fun getModifiedValue(): Int {
return someValue
}
}
class TestEnvironment {
fun testType(superClass: SuperClass<SuperType>) {
// do something with superClass
}
fun itDoesntWork() {
testType(ChildClass()) // compilation error
}
}
以下是the gist和the kotlin playground
期望的结果是该功能 testType(superClass: SuperClass<SuperType>)
应该接受类 ChildClass()
而不使用*
通配符
答案 0 :(得分:4)
generics variance阻止您的代码正常工作。 SuperClass
定义为
open class SuperClass<T> where T: SuperType { ... }
其类型参数T
被声明为不变(它没有out
或in
修饰符)。因此,子类型关系如下:
DerivedClass<ChildType>
不 <{1}} SuperClass<SuperType>
不 <{1}} SuperClass<ChildType>
是 SuperClass<SuperType>
的子类型。由于函数参数应属于参数类型的子类型,而DerivedClass<SuperType>
实际上是SuperClass<SuperType>
,因此您无法将ChildClass
作为DerivedClass<ChildType>
传递。
您可以通过将out
projection添加到参数类型ChildClass
来解决此问题:
SuperClass<SuperType>
这基本上意味着此函数接受testType
,其中fun testType(superClass: SuperClass<out SuperType>)
是SuperClass<T>
的子类型。当然,它对T
用法添加了一些限制:因为SuperType
可以绝对是superClass
的任何子类型,所以将任何内容传递给期望{{1}的函数都不是类型安全的作为参数,这是禁止的。
此外,请参阅另一个解释不变泛型行为的原因的答案:(link)