我试图编写一些通用代码,但无法摆脱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>也不是彼此的子类型,除非由方差修饰符inout(或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>也不是。

    10-01 22:16