期望意外类型的 Kotlin 泛型

Kotlin generics expecting unexpected type

我已经用两个泛型类型定义了以下基础 class 并使用它两层深(因为缺少更好的短语)。这是我的用例。

abstract class BasePresenter<out M, out V> {
    var model: M? = null

    var view: WeakReference<V>? = null

    fun setM(model: M?): Unit {
        this.model = model

        if (setupDone()) {
            updateView()
        }
    }

    fun bindView(view: V) {
        this.view = WeakReference(view)
    }

    fun unbindView() {
        this.view = null
    }

    abstract fun updateView()

    fun view(): V? {
        return if (view == null) null else view?.get()
    }

    fun setupDone(): Boolean {
        return view() != null && model != null
    }
}

我正在使用

扩展它
open class VenueListPresenter: BasePresenter<Venue, VenueView>()  {...}

正如预期的那样工作正常,但是当我尝试在另一个 class 中使用 VenuListPresenter 作为类型参数时,我 运行 遇到了问题。

open class VenuesViewHolder(itemView: View): MvpViewHolder<VenueListPresenter>(itemView) {

这给了我一个错误,指出 MvpViewHolder 中的预期参数是 BasePresenter,而找到的是 VenueListPresenter。我的 VenueListPresenter 扩展了 BasePresenter<Venue, VenueView>,其中 VenueVenueViewAny? 类型,因为默认情况下它们扩展了它。那为什么它不起作用?

MvpViewHolder 是这样定义的

abstract class MvpViewHolder<P>(itemView: View) : RecyclerView.ViewHolder(itemView) where P : BasePresenter<Any?, Any?>

您需要向 BasePresenter 中的泛型参数添加 out 方差,这样像 BasePresenter<Venue, VenueView> 这样的类型将成为 BasePresenter<Any?, Any?>.[=36= 的子类型]

abstract class BasePresenter<out M, out V>

作为简短说明,out 关键字指定 协方差 ,例如如果你有 class YourClass<out T>,这意味着当 AB 的子类型时,那么 YourClass<A> 也是 YourClass<B> 的子类型.

docs 中查看有关 Kotlin 泛型和变体的更多详细信息。


根据以下评论进行编辑:

如果您不能进行上述更改,您可以在 MvpViewHolder class 处使用 使用网站差异 来接受 BasePresenter 子类型在其类型参数中具有 Any? 的任何子类型:

abstract class MvpViewHolder<P>(itemView: View) : RecyclerView.ViewHolder(itemView) 
        where P : BasePresenter<out Any?, out Any?>

你可以用 star projection 做同样的事情(在这种情况下只是语法不同):

abstract class MvpViewHolder<P>(itemView: View) : RecyclerView.ViewHolder(itemView) 
        where P : BasePresenter<*, *>

在这两种情况下,从 P 返回的 VM 类型的任何内容都将是 Any? 类型,您将无法将 VM 实例传递给 P 的方法。如果您需要能够做到这一点,您可以考虑添加更多通用参数:

abstract class MvpViewHolder<P, M, V>(itemView: View) : RecyclerView.ViewHolder(itemView)
        where P : BasePresenter<M, V>