期望意外类型的 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>
,其中 Venue
和 VenueView
是 Any?
类型,因为默认情况下它们扩展了它。那为什么它不起作用?
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>
,这意味着当 A
是 B
的子类型时,那么 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
返回的 V
或 M
类型的任何内容都将是 Any?
类型,您将无法将 V
或 M
实例传递给 P
的方法。如果您需要能够做到这一点,您可以考虑添加更多通用参数:
abstract class MvpViewHolder<P, M, V>(itemView: View) : RecyclerView.ViewHolder(itemView)
where P : BasePresenter<M, V>
我已经用两个泛型类型定义了以下基础 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>
,其中 Venue
和 VenueView
是 Any?
类型,因为默认情况下它们扩展了它。那为什么它不起作用?
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>
,这意味着当 A
是 B
的子类型时,那么 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
返回的 V
或 M
类型的任何内容都将是 Any?
类型,您将无法将 V
或 M
实例传递给 P
的方法。如果您需要能够做到这一点,您可以考虑添加更多通用参数:
abstract class MvpViewHolder<P, M, V>(itemView: View) : RecyclerView.ViewHolder(itemView)
where P : BasePresenter<M, V>