Kotlin 泛型:Kotlin 无法通过正确的继承识别我的 class
Kotlin Generics: Kotlin does not recognize my class with correct inheritance
这是我的简化示例:
interface IMyView
interface IMyViewModel<VIEW : IMyView, in ITEM> {
fun attachView(view: VIEW)
fun getView(): VIEW?
}
class myView : IMyView
class MyViewModel : IMyViewModel<myView, String> {
override fun attachView(view: myView) {
TODO("not implemented")
}
override fun getView(): myView? {
TODO("not implemented")
}
}
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>> : IMyView {
protected lateinit var viewModel: VIEWMODEL
fun myInvocation(): Unit {
viewModel.attachView(this as IMyView)
}
}
class MyMainClass : MyBaseClass<MyViewModel>()
问题出在最后一行,因为 MyViewModel 未被识别为 IMyViewModel。报错信息如下:
Type argument is not within its bounds.
Expected: IMyViewModel<IMyView, *>
Found: MyViewModel
在 Java 中有效。我必须进行哪些调整才能使其在 Kotlin 中也能正常工作?
****** 更新 ******
如果你使用
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>>
(请参阅上面更新的 Kotlin 代码)
然后我无法调用 myInvocation,因为对于该调用我需要 'in IMyView'。
因此,这是一场灾难。我所做的一切都会导致其他问题。在 Java.
中更容易
你的代码的问题是,当你设定一个上限 VIEWMODEL : IMyViewModel<IMyView, *>
时,一个类型可以满足这个界限 只有 如果它实现 IMyViewModel
VIEW
类型参数将 完全 替换为 IMyView
,不允许 IMyView
的子类型(因此 MyViewModel
被拒绝)。换句话说,VIEW
is invariant.
由于 Kotlin 允许您在声明点和使用点都指定类型参数差异,您可以通过执行以下操作之一来解决此问题:
使 IMyViewModel
的 VIEW
类型参数与声明位置方差协变:
interface IMyViewModel<out VIEW : IMyView, in ITEM>
^^^
在VIEWMODEL
上界的IMyViewModel
的使用位置添加一个out
投影:
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>>
^^^
将另一个类型参数T
添加到MyBaseClass
并在IMyViewModel<T, *>
中使用它:
abstract class MyBaseClass<T : IMyView, VIEWMODEL : IMyViewModel<T, *>>
class MyMainClass: MyBaseClass<myView, MyViewModel>()
我现在解决了这个问题。我犯了一个概念错误。这是解决方案:
interface IMyViewModel<VIEW : IMyView, in ITEM> {
fun attachView(view: VIEW)
fun getView(): VIEW?
}
class MyViewModel : IMyViewModel<IMyView, String> {
override fun attachView(view: IMyView) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getView(): IMyView? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<IMyView, *>> : IMyView {
protected lateinit var viewModel: VIEWMODEL
fun myInvocation(): Unit {
viewModel.attachView(this)
}
}
class MyMainClass : MyBaseClass<MyViewModel>()
这是我的简化示例:
interface IMyView
interface IMyViewModel<VIEW : IMyView, in ITEM> {
fun attachView(view: VIEW)
fun getView(): VIEW?
}
class myView : IMyView
class MyViewModel : IMyViewModel<myView, String> {
override fun attachView(view: myView) {
TODO("not implemented")
}
override fun getView(): myView? {
TODO("not implemented")
}
}
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>> : IMyView {
protected lateinit var viewModel: VIEWMODEL
fun myInvocation(): Unit {
viewModel.attachView(this as IMyView)
}
}
class MyMainClass : MyBaseClass<MyViewModel>()
问题出在最后一行,因为 MyViewModel 未被识别为 IMyViewModel。报错信息如下:
Type argument is not within its bounds.
Expected: IMyViewModel<IMyView, *>
Found: MyViewModel
在 Java 中有效。我必须进行哪些调整才能使其在 Kotlin 中也能正常工作?
****** 更新 ******
如果你使用
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>>
(请参阅上面更新的 Kotlin 代码)
然后我无法调用 myInvocation,因为对于该调用我需要 'in IMyView'。 因此,这是一场灾难。我所做的一切都会导致其他问题。在 Java.
中更容易你的代码的问题是,当你设定一个上限 VIEWMODEL : IMyViewModel<IMyView, *>
时,一个类型可以满足这个界限 只有 如果它实现 IMyViewModel
VIEW
类型参数将 完全 替换为 IMyView
,不允许 IMyView
的子类型(因此 MyViewModel
被拒绝)。换句话说,VIEW
is invariant.
由于 Kotlin 允许您在声明点和使用点都指定类型参数差异,您可以通过执行以下操作之一来解决此问题:
使
IMyViewModel
的VIEW
类型参数与声明位置方差协变:interface IMyViewModel<out VIEW : IMyView, in ITEM> ^^^
在
VIEWMODEL
上界的IMyViewModel
的使用位置添加一个out
投影:abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>> ^^^
将另一个类型参数
T
添加到MyBaseClass
并在IMyViewModel<T, *>
中使用它:abstract class MyBaseClass<T : IMyView, VIEWMODEL : IMyViewModel<T, *>> class MyMainClass: MyBaseClass<myView, MyViewModel>()
我现在解决了这个问题。我犯了一个概念错误。这是解决方案:
interface IMyViewModel<VIEW : IMyView, in ITEM> {
fun attachView(view: VIEW)
fun getView(): VIEW?
}
class MyViewModel : IMyViewModel<IMyView, String> {
override fun attachView(view: IMyView) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getView(): IMyView? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
abstract class MyBaseClass<VIEWMODEL : IMyViewModel<IMyView, *>> : IMyView {
protected lateinit var viewModel: VIEWMODEL
fun myInvocation(): Unit {
viewModel.attachView(this)
}
}
class MyMainClass : MyBaseClass<MyViewModel>()