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>
Venue
和VenueView
是Any?
类型的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>
,则意味着当A
是B
的子类型时,则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
返回的任何类型的V
或M
将是Any?
类型的Any?
,你将无法将V
或M
实例传递给P
方法。 如果你需要做到这一点,你可以考虑添加更多的通用参数:
abstract class MvpViewHolder<P, M, V>(itemView: View) : RecyclerView.ViewHolder(itemView) where P : BasePresenter<M, V>