Kotlin泛型超/儿童班
试图使用泛型类,但有以下问题,即:
类型不匹配:推断的类型是
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 } }
这是要点和kotlin操场
期望的结果是函数 testType(superClass: SuperClass<SuperType>)
应该接受类 ChildClass()
而不使用*
通配符
这是泛型方差 ,阻止你的代码工作。 SuperClass
被定义为
open class SuperClass<T> where T: SuperType { ... }
而它的类型参数T
被声明为不变(它没有out
或in
修饰符)。 因此子类型关系如下:
-
DerivedClass<ChildType>
不是SuperClass<SuperType>
的子类型 -
SuperClass<ChildType>
不是SuperClass<SuperType>
的子类型 -
DerivedClass<SuperType>
是DerivedClass<SuperType>
的子类型。
由于函数参数应该属于参数类型的子类型,并且ChildClass
实际上是DerivedClass<ChildType>
,所以不能将ChildClass
作为SuperClass<SuperType>
传递。
您可以通过将out
投影添加到testType
的参数类型来解决此问题:
fun testType(superClass: SuperClass<out SuperType>)
这基本上意味着这个函数接受SuperClass<T>
,其中T
是SuperType
的子类型。 当然,它增加了对superClass
用法的一些限制:因为T
可以是SuperType
任何子类型,所以将任何东西传递给期望T
作为参数的函数并不是类型安全的,这是被禁止的。
另请参阅另一个解释不变泛型行为的原因:( 链接)