Kotlin 泛型方法和继承
Kotlin generic methods and inheritance
在我的代码中,我想在抽象 class 中创建一个方法,其中 return 是一些 Observable。然后这个抽象 class 的实现将 return 某些(指定)类型的 Observable。不幸的是 Android Studio 将 return 在实现 method():
中出错 "Type mismatch"
- 预期:可观察
- 找到:Observable<{package}.DrawerItemEntity>
我的 MockDrawerList.getList()
returns Observable<DrawerItemEntity>
请关注execute()
和buildUseCaseObservable
摘要class
public abstract class UseCase(threadExecutor: ThreadExecutor,
postExecutionThread: PostExecutionThread) {
private val threadExecutor: ThreadExecutor
private val postExecutionThread: PostExecutionThread
private var subscription: Subscription = Subscriptions.empty()
init {
this.postExecutionThread = postExecutionThread
this.threadExecutor = threadExecutor
}
protected abstract fun buildUseCaseObservable(): Observable<Any>
public fun execute(useCaseSubsriber: Subscriber<Any>) {
subscription = buildUseCaseObservable()
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(useCaseSubsriber)
}
public fun unsubsribe() {
if (!subscription.isUnsubscribed())
subscription.unsubscribe()
}
}
实施
Inject
class GetDrawerListUseCase(threadExecutor: ThreadExecutor,
postExecutionThread:PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
override fun buildUseCaseObservable(): Observable<Any> {
return MockDrawerList.getList()
}
}
尽管 String
是 Any
的子类型,但 Observable<String>
在 Kotlin 中 而不是 被视为 Observable<Any>
的子类型.您应该使用 use-site variance:将 buildUseCaseObservable
的 return 类型更改为 Observable<out Any>
或 Observable<*>
(后者相当于Observable<out Any?>
),代码应该可以编译。
为什么泛型类型的继承不能根据它们的类型参数自动工作?这是 Joshua Bloch 在 Effective Java,Item 28: Use bounded wildcards to increase API flexibility 中最好解释的问题。简而言之,只有当类型保证不使用其类型参数的实例时,这才有效,即如果带有泛型参数 T
的 class 没有将 T
作为参数的方法一个参数。在 Kotlin 中可以强制执行的一种方法是 declaration-site variance,例如集合接口(kotlin.Collection
、kotlin.List
、...)就是这种情况。
但是,Observable
当然不是 Kotlin class,因此编译器无法知道 Observable<String>
可以安全地用于 Observable<Any>
预期的。因此,我们必须手动告诉编译器我们可以只使用 Observable<T>
的一部分不将 T
作为参数的功能,这样我们将获得很好的继承。这种 "subset type" 在 Kotlin 中称为 type projection,该技术称为使用位置差异。
您可以在官方语言文档的 Generics.
部分中阅读有关 Kotlin 中声明和使用位置差异的更多信息
在我的代码中,我想在抽象 class 中创建一个方法,其中 return 是一些 Observable。然后这个抽象 class 的实现将 return 某些(指定)类型的 Observable。不幸的是 Android Studio 将 return 在实现 method():
中出错 "Type mismatch"- 预期:可观察
- 找到:Observable<{package}.DrawerItemEntity>
我的 MockDrawerList.getList()
returns Observable<DrawerItemEntity>
请关注execute()
和buildUseCaseObservable
摘要class
public abstract class UseCase(threadExecutor: ThreadExecutor,
postExecutionThread: PostExecutionThread) {
private val threadExecutor: ThreadExecutor
private val postExecutionThread: PostExecutionThread
private var subscription: Subscription = Subscriptions.empty()
init {
this.postExecutionThread = postExecutionThread
this.threadExecutor = threadExecutor
}
protected abstract fun buildUseCaseObservable(): Observable<Any>
public fun execute(useCaseSubsriber: Subscriber<Any>) {
subscription = buildUseCaseObservable()
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(useCaseSubsriber)
}
public fun unsubsribe() {
if (!subscription.isUnsubscribed())
subscription.unsubscribe()
}
}
实施
Inject
class GetDrawerListUseCase(threadExecutor: ThreadExecutor,
postExecutionThread:PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
override fun buildUseCaseObservable(): Observable<Any> {
return MockDrawerList.getList()
}
}
尽管 String
是 Any
的子类型,但 Observable<String>
在 Kotlin 中 而不是 被视为 Observable<Any>
的子类型.您应该使用 use-site variance:将 buildUseCaseObservable
的 return 类型更改为 Observable<out Any>
或 Observable<*>
(后者相当于Observable<out Any?>
),代码应该可以编译。
为什么泛型类型的继承不能根据它们的类型参数自动工作?这是 Joshua Bloch 在 Effective Java,Item 28: Use bounded wildcards to increase API flexibility 中最好解释的问题。简而言之,只有当类型保证不使用其类型参数的实例时,这才有效,即如果带有泛型参数 T
的 class 没有将 T
作为参数的方法一个参数。在 Kotlin 中可以强制执行的一种方法是 declaration-site variance,例如集合接口(kotlin.Collection
、kotlin.List
、...)就是这种情况。
但是,Observable
当然不是 Kotlin class,因此编译器无法知道 Observable<String>
可以安全地用于 Observable<Any>
预期的。因此,我们必须手动告诉编译器我们可以只使用 Observable<T>
的一部分不将 T
作为参数的功能,这样我们将获得很好的继承。这种 "subset type" 在 Kotlin 中称为 type projection,该技术称为使用位置差异。
您可以在官方语言文档的 Generics.
部分中阅读有关 Kotlin 中声明和使用位置差异的更多信息