将改造的回报转换为Either <T,R>

时间:2019-10-24 18:01:07

标签: android kotlin retrofit

由于我的api调用,我使用ResultWrapper如下:

sealed class ResultWrapper<out T> {
    data class Success<T>(val data: T) : ResultWrapper<T>()
    data class Unauthorized<T>(val exception: UnauthorizedException) : ResultWrapper<T>()
    //More error classes
}

使用ResultWrapper.时,我无法获得T:

when(function) {
 is ResultWrapper.Success -> DoSomething
 is ResultWrapper.SomeError -> DoSomething

我意识到我无法使用它的返回值,所以我找到了这个密封的类

sealed class Either<out L, out R> {
    //Failure
    data class Left<out L>(val value: L) : Either<L, Nothing>()
    //Success
    data class Right<out R>(val value: R) : Either<Nothing, R>()
    val isRight get() = this is Right<R>
    val isLeft get() = this is Left<L>
    fun <L> left(a: L) = Left(a)
    fun <R> right(b: R) = Right(b)
}
fun <L, R, T> Either<L, R>.fold(left: (L) -> T, right: (R) -> T): T =
    when (this) {
        is Either.Left  -> left(value)
        is Either.Right -> right(value)
    }
fun <L, R, T> Either<L, R>.flatMap(f: (R) -> Either<L, T>): Either<L, T> =
    fold({ this as Either.Left }, f)
fun <L, R, T> Either<L, R>.map(f: (R) -> T): Either<L, T> =
    flatMap { Either.Right(f(it)) }

有了这个我就可以做到,事情是我正在使用它:

inline fun <reified T : Any> execute(requestFunc: () -> T): ResultWrapper<T> =
        try {
            ResultWrapper.Success(requestFunc.invoke())
        } catch (exception: Exception) {
            when (exception) {
                is UnauthorizedException -> ResultWrapper.Unauthorized(exception)
                is NetworkException -> ResultWrapper.Network(exception)
                is BadRequestException -> ResultWrapper.BadRequest(exception)
                is NotFoundException -> ResultWrapper.NotFound(exception)
                else -> ResultWrapper.Error(exception)
            }
        }

然后尝试将其移动到Either时遇到了问题,因为我必须执行类似reified T,R的操作,返回值是Either<T,R>,但随后尝试执行{{1} }表示期望T,R,而我只返回T。 有什么想法要实现吗?

编辑

我知道如何使用Either.Right(requestFunc.invoke()),但是我想知道如何使用ResultWrapper,所以我可以使用Either并获得两个结果。

我这样做的方法是使用: fold()

1 个答案:

答案 0 :(得分:0)

因此,您想使用Either<L, R>。然后,您需要为成功的结果指定类型(可以仅为T),为失败的类型指定。对于后者,如果您需要区分不同类型的失败,您仍然必须引入类似密封类的东西:

sealed class Failure(val cause: Exception) {
    class Unauthorized(cause: Exception) : Failure(cause)
    class Network(cause: Exception) : Failure(cause)
    class BadRequest(cause: Exception) : Failure(cause)
    class NotFound(cause: Exception) : Failure(cause)
    class Error(cause: Exception) : Failure(cause)
}

然后您可以实现execute来以这种方式返回Either

inline fun <reified T : Any> execute(requestFunc: () -> T): Either<Failure, T> =
        try {
            Either.Right(requestFunc.invoke())
        } catch (exception: Exception) {
            Either.Left(when (exception) {
                is UnauthorizedException -> Failure.Unauthorized(exception)
                is NetworkException -> Failure.Network(exception)
                is BadRequestException -> Failure.BadRequest(exception)
                is NotFoundException -> Failure.NotFound(exception)
                else -> Failure.Error(exception)
            })
        }

通常,代表成功结果的类型用作R类型参数或Either<L, R>,失败类型用作L