Kotlin泛型期待意想不到的类型

我用两个泛型定义了下面的基类,并使用它深两层(缺少一个更好的短语)。 这是我的用例。

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>() {...} 

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

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

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

MvpViewHolder是这样定义的

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

您需要在BasePresenter参数添加out方差中,以便类似BasePresenter<Venue, VenueView>的类型将成为BasePresenter<Any?, Any?>的子类型。

 abstract class BasePresenter<out M, out V> 

作为一个简短的解释, out关键字指定协方差 ,例如,如果您有一个YourClass<out T> ,则意味着当AB的子类型时,则YourClass<A>也是YourClass<B>的子类型。

在文档中查看关于Kotlin泛型和变化的更多细节。


根据以下评论编辑:

如果您无法进行上述更改,则可以使用MvpViewHolder类中的使用站点差异来接受BasePresenter类型的BasePresenter子类型Any? 在他们的类型参数:

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

你可以用星型投影完成同样的事情(在这种情况下只是一个不同的语法):

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

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

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