简体   繁体   English

Kotlin通用方法和继承

[英]Kotlin generic methods and inheritance

In my code I would like to create a method in an abstract class, which returns some Observable. 在我的代码中,我想在抽象类中创建一个方法,该方法返回一些Observable。 Then implementation of this abstract class would return Observable of certain (specified) type. 然后,此抽象类的实现将返回某些(指定)类型的Observable。 Unfortunately Android Studio will return an error "Type mismatch" in implementation method(): 不幸的是,Android Studio将在实现method()中返回错误“类型不匹配”:

  • Expected: Observable 预期:可观察
  • Found: Observable<{package}.DrawerItemEntity> 找到的:Observable <{package} .DrawerItemEntity>

My MockDrawerList.getList() returns Observable<DrawerItemEntity> 我的MockDrawerList.getList()返回Observable<DrawerItemEntity>

please focus on execute() and buildUseCaseObservable 请专注于execute()buildUseCaseObservable

Abstract 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()
    }
}

Implementation 实作

Inject
class GetDrawerListUseCase(threadExecutor: ThreadExecutor, 
postExecutionThread:PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {

    override fun buildUseCaseObservable(): Observable<Any> {
        return MockDrawerList.getList()
    }
}

Even though String is a subtype of Any , Observable<String> is not considered a subtype of Observable<Any> in Kotlin. 即使StringAny的子类型,在Kotlin中, Observable<String> 也不被视为Observable<Any>的子类型。 You should use use-site variance : change buildUseCaseObservable 's return type to Observable<out Any> or Observable<*> (the latter is equivalent to Observable<out Any?> ) and the code should compile. 您应该使用使用场所差异 :将buildUseCaseObservable的返回类型更改为Observable<out Any>Observable<*> (后者等效于Observable<out Any?> ),并且代码应编译。

Why doesn't inheritance for generic types work automatically based on their type parameters? 为什么通用类型的继承不能基于其类型参数自动工作? This is a problem best explained by Joshua Bloch in Effective Java, Item 28: Use bounded wildcards to increase API flexibility. 这是Joshua Bloch在Effective Java,第28项:使用有界通配符提高API灵活性中最好地解释的一个问题。 To put very simply, this can work only when the type is guaranteed not to consume instances of its type parameters, ie if a class with a generic parameter T has no methods taking T as a parameter. 简单地说,这仅在保证类型不使用其类型参数实例的情况下才有效,即,如果具有通用参数T的类没有使用T作为参数的方法。 One way this can be enforced in Kotlin is by declaration-site variance , which is the case for example for collection interfaces ( kotlin.Collection , kotlin.List , ...). 在Kotlin中可以强制执行此操作的一种方法是通过声明站点差异 ,例如对于集合接口( kotlin.Collectionkotlin.List ,...)。

However, Observable is of course not a Kotlin class, so the compiler has no way of knowing that Observable<String> can be used safely where an Observable<Any> is expected. 但是, Observable当然不是Kotlin类,因此编译器无法知道在需要Observable<Any>地方可以安全地使用Observable<String>方法。 So we have to manually tell the compiler that we're OK with using only a subset of features of Observable<T> that don't take T as a parameter, so that we will get the nice inheritance instead. 因此,我们必须手动告诉编译器,我们只使用Observable<T>的功能子集(不使用T作为参数)就可以了,这样我们将获得很好的继承。 This "subset type" is called a type projection in Kotlin and the technique is called use-site variance. 这种“子集类型”在Kotlin中称为类型投影 ,而该技术称为使用地点差异。

You can read more about declaration- and use-site variance in Kotlin in the official language documentation, section Generics . 您可以在官方语言文档“ 泛型”部分中阅读有关Kotlin中声明和使用场所差异的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM