如果提供为RxJava Observable,则必须将Kotlin密封类子类强制转换为基类 [英] Kotlin sealed class subclass needs to be casted to base class if provided as RxJava Observable

查看:87
本文介绍了如果提供为RxJava Observable,则必须将Kotlin密封类子类强制转换为基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在用Kotlin编写的应用程序中避免RxJava链的终端状态,所以我发现将Observable<T>转换为Observable<Result<T>>(其中Result是密封类)是正确的.

 sealed class Result<T>
data class Success<T>(val data: T) : Result<T>()
data class Failure<T>(val throwable: Throwable) : Result<T>()
 

我们可以观察到这个网络请求.

 fun getOrganization(): Observable<Result<Boolean>> {
    return api.getOrganization("google")
            .map { Success(true) }
            .onErrorReturn { Failure(RuntimeException("throwable")) }
}
 

所以我最后要做的就是处理这样的结果.

 fun main(args: Array<String>) {
    getOrganization().subscribe({
        when (it) {
            is Success -> print("success = ${it.data}")
            is Failure -> print("failure = ${it.throwable}")
        }
    })
}
 

一切正常,但在IDE中出现此错误.

使用子类而不是基类不是很简单吗?

我发现,如果我明确将Success(true)强制转换为Result<Boolean>,则一切正常,但会显示此警告.

为什么甚至发生这种情况,我在这里做错了什么?

UPD. 似乎这里的主要问题是在rxjava的onErrorReturn运算符附近.如果我将其完全删除,则即使没有out关键字(如答案建议)也可以使用它.

如果我同时从map和onErrorReturn返回Success,则out关键字有助于消除错误.

但是,如果我从onErrorReturn返回Failure,仍然会出现错误.编译器必须知道Failure Result的键入方式与Success相同.我应该怎么做才能避免它或满足它的要求?

解决方案

也许您误解了kotlin中的一般差异.它工作正常,因为Success<Boolean>Result<Boolean>的子类型.因此报告了"不需要强制投放"警告,并且以下代码可以正常运行:

val ok:Success<Boolean>  = Success(true);
val result:Result<Boolean>  = ok;

但是但是您不能将Success<Boolean>分配给Result<Any>,因为它们的类型参数不同,所以这就是为什么编译器报告"类型不匹配"错误,例如:

val ok:Success<Boolean>  = Success(true);
val result1:Result<Any>  = ok;// error
val result2:Result<out Any>  = ok;// ok

要修复错误和警告,您可以尝试以下代码:

fun getOrganization(): Observable<out Result<Boolean>> {
    return api.getOrganization("google")
            .map<Result<Boolean>> { Success(true) }
            .onErrorReturn { Failure(RuntimeException("throwable")) }
}

有关更多详细信息,请参见 java通用子类型 & kotlin类型投影.

I'm trying to avoid terminal states of RxJava chains in my app written in Kotlin, so I found out that it is right thing to transform Observable<T> to Observable<Result<T>> where Result is sealed class.

sealed class Result<T>
data class Success<T>(val data: T) : Result<T>()
data class Failure<T>(val throwable: Throwable) : Result<T>()

And let's say I have this network request observable.

fun getOrganization(): Observable<Result<Boolean>> {
    return api.getOrganization("google")
            .map { Success(true) }
            .onErrorReturn { Failure(RuntimeException("throwable")) }
}

So what I want to do in the end is to handle result like this.

fun main(args: Array<String>) {
    getOrganization().subscribe({
        when (it) {
            is Success -> print("success = ${it.data}")
            is Failure -> print("failure = ${it.throwable}")
        }
    })
}

Everything should work great, but I have this error in IDE.

Isn't it just simple using of subclass instead of base class?

I found out that if I explicitly cast Success(true) to Result<Boolean> everything works, but shows this warning.

Why it even happens and what am I doing wrong here?

UPD. It looks like the main issue here is near rxjava's onErrorReturn operator. If I remove it completely, then it works even without out keyword like answers suggest.

If I return Success from both map and onErrorReturn then out keyword helps to get rid of errors.

But if I return Failure from onErrorReturn there's still error. Compiler has to know that Failure Result typed with the same Boolean as Success. What should I do to avoid it or to satisfy it's requirements?

解决方案

maybe you misunderstand the generic variance in kotlin. it works fine since Success<Boolean> is a subtype of Result<Boolean>. so the "No need cast" warning reported and the code below works fine:

val ok:Success<Boolean>  = Success(true);
val result:Result<Boolean>  = ok;

But you can't assign a Success<Boolean> to a Result<Any> since their type parameters are different, so this why compiler reports the "Type mismatch" error , for example:

val ok:Success<Boolean>  = Success(true);
val result1:Result<Any>  = ok;// error
val result2:Result<out Any>  = ok;// ok

to fix the error and warnings you can try the code below:

fun getOrganization(): Observable<out Result<Boolean>> {
    return api.getOrganization("google")
            .map<Result<Boolean>> { Success(true) }
            .onErrorReturn { Failure(RuntimeException("throwable")) }
}

for more details, you can see java generic subtypes & kotlin type projections.

这篇关于如果提供为RxJava Observable,则必须将Kotlin密封类子类强制转换为基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆