我试图编写一些通用代码,但无法摆脱Type of 'PROPERTY' is not a subtype of the overridden property
错误。
我的代码的简化版本:
abstract class BaseP<V> {
var view: V? = null
}
abstract class BaseF {
fun smth() {
pp.view = this
}
abstract val pp: BaseP<BaseF>
}
abstract class SubF: BaseF() {
abstract override val pp: BaseP<SubF>
// Error:(20, 30) Type of 'pp' is not a subtype of the overridden property 'public abstract val pp: BaseP<BaseF> defined in BaseF'
}
我发现错误可以是
@Suppress
-ed,但是我怀疑这是最好且唯一的方法。有更好的东西吗?毕竟我不明白,为什么
subtypeA<subtypeB>
不算作baseA<baseB>
的子类型,有人可以解释一下吗? 最佳答案
首先,SubtypeA<B>
是BaseA<B>
的子类型,因此问题出在泛型参数子类型化中。
答案在于Kotlin generics variance,它类似于that of Java。
泛型默认情况下是不变的,这意味着,即使在更简单的情况下,对于类A<T>
,A<SubtypeB>
和A<BaseB>
也不是彼此的子类型,除非由方差修饰符in
和out
(或Java wildcards)另外指定。
有两种情况:
T
的实例中取出A
实例,则可以使用out
修饰符:A<out T>
。在这里
A<SubtypeB>
成为A<BaseB>
的子类型,因为从A<SubtypeB>
显然您可以获取BaseB
的实例,反之亦然。 T
传递到类的方法中,则在类声明中使用in
修饰符:A<in T>
。这里
A<BaseB>
是A<SubtypeB>
的子类型,因为A<BaseB>
的每个实例也可以将SubtypeB
接收到方法中,但反之则不然。 如果您都将
T
传递到类A<T>
并从中获取,那么T
的唯一选择就是保持不变,这样A<SubB>
和A<SuperB>
都不是A<B>
的子类型:否则会导致上述矛盾。确实是这样:在
BaseP<B>
中,您都将V
的项都放入view
属性中,因此V
只能是不变的,并且BaseP<SubF>
并不是BaseP<BaseF>
的子类型,SubP<SubF>
也不是。